From f7ee43c27d2f11d5ffc2059805dfab5ff3f661c7 Mon Sep 17 00:00:00 2001 From: xGinko Date: Sat, 4 Jan 2025 22:47:53 +0100 Subject: [PATCH] 2.7.3 release --- AnarchyExploitFixesFolia/build.gradle.kts | 1 - .../me/xginko/aef/AnarchyExploitFixes.java | 124 +- .../java/me/xginko/aef/commands/HelpCmd.java | 4 +- .../java/me/xginko/aef/commands/SayCmd.java | 4 +- .../aef/commands/ToggleConnectionMsgsCmd.java | 6 +- .../me/xginko/aef/commands/aef/AEFCmd.java | 24 +- .../aef/subcommands/DisableSubCmd.java | 8 +- .../aef/subcommands/ElytraSubCmd.java | 4 +- .../aef/subcommands/GearedSubCmd.java | 4 +- .../commands/aef/subcommands/LagSubCmd.java | 14 +- .../aef/subcommands/ReloadSubCmd.java | 6 +- .../aef/subcommands/VersionSubCmd.java | 4 +- .../subcommands/bytesize/ByteSizeSubCmd.java | 7 +- .../subcommands/bytesize/InventorySubCmd.java | 6 +- .../aef/subcommands/bytesize/ItemSubCmd.java | 6 +- .../java/me/xginko/aef/config/Config.java | 5 +- .../me/xginko/aef/config/LanguageCache.java | 9 +- .../aef/events/PacketPlayerRespawnEvent.java | 37 - .../me/xginko/aef/listeners/AEFListener.java | 45 - .../PacketPlayerRespawnListener.java | 73 - .../java/me/xginko/aef/modules/AEFModule.java | 105 +- .../bedrock/FillNetherCeilingOnChunkload.java | 15 +- .../bedrock/FillNetherFloorOnChunkload.java | 17 +- .../FillOverworldFloorOnChunkload.java | 17 +- .../PeriodicallyFillNetherCeiling.java | 27 +- .../bedrock/PeriodicallyFillNetherFloor.java | 23 +- .../PeriodicallyFillOverworldFloor.java | 25 +- .../PreventGoingBelowBedrockFloor.java | 9 +- .../modules/chat/PreventPluginScanning.java | 15 +- .../commandwhitelist/CommandWhitelist.java | 51 +- .../aef/modules/chunklimits/BlockLimit.java | 79 +- .../chunklimits/CustomEntityLimit.java | 31 +- .../modules/chunklimits/DroppedItemLimit.java | 49 +- .../modules/chunklimits/ExpBottleLimit.java | 99 - .../chunklimits/FallingBlockLimit.java | 28 +- .../modules/chunklimits/MinecartLimit.java | 21 +- .../chunklimits/NonLivingEntityLimit.java | 27 +- .../modules/chunklimits/ProjectileLimit.java | 141 + .../modules/chunklimits/TileEntityLimit.java | 28 +- .../aef/modules/chunklimits/VehicleLimit.java | 23 +- .../modules/chunklimits/VillagerLimit.java | 26 +- .../me/xginko/aef/modules/combat/BowBomb.java | 7 +- .../me/xginko/aef/modules/combat/Burrow.java | 19 +- .../xginko/aef/modules/combat/MultiTask.java | 7 +- .../modules/combat/PistonCrystalDelay.java | 32 +- .../xginko/aef/modules/combat/PistonPush.java | 14 +- .../aef/modules/combat/PortalGodMode.java | 24 +- .../aef/modules/combat/SilentSwapDelay.java | 41 +- .../modules/combat/auras/AnchorAuraDelay.java | 6 +- .../modules/combat/auras/AuraDelayModule.java | 26 +- .../combat/auras/CrystalAuraDelay.java | 2 +- .../modules/dupepreventions/AllayDupe.java | 62 + .../dupepreventions/BookTitleDupe.java | 78 + .../ChestedEntitiesInPortals.java | 12 +- .../dupepreventions/ChestsOnEntities.java | 8 +- .../CloseEntityInventoriesOnLogout.java | 8 +- .../CloseEntityInventoryOnChunkUnload.java | 8 +- .../aef/modules/elytra/ElytraAtSpawn.java | 14 +- .../aef/modules/elytra/ElytraGlobal.java | 26 +- .../aef/modules/elytra/ElytraHelper.java | 30 +- .../aef/modules/elytra/ElytraOnCeiling.java | 19 +- .../aef/modules/elytra/ElytraPacketFly.java | 25 +- .../illegals/items/BannedItemNames.java | 36 +- .../illegals/items/BannedMaterials.java | 20 +- .../illegals/items/IllegalItemModule.java | 160 +- .../illegals/items/IllegalPotions.java | 22 +- .../illegals/items/InvalidStackSize.java | 26 +- .../illegals/items/ItemAttributes.java | 22 +- .../modules/illegals/items/PlayerHeads.java | 18 +- .../aef/modules/illegals/items/SpawnEggs.java | 20 +- .../modules/illegals/items/Unbreakables.java | 32 +- .../items/enchantments/HigherEnchants.java | 37 +- .../enchantments/InapplicableEnchants.java | 22 +- .../enchantments/IncompatibleEnchants.java | 108 +- .../illegals/items/nbt/CommandItems.java | 14 +- .../illegals/items/nbt/CustomNBTFilter.java | 24 +- .../items/nbt/NBTFilledStorageItem.java | 28 +- .../PeriodicallyRemoveIllegalBlocks.java | 51 +- .../RemoveIllegalBlocksOnChunkload.java | 54 +- .../placedblocks/RemoveUnnaturalSpawners.java | 79 +- .../lagpreventions/DisableCustomEntities.java | 71 + .../lagpreventions/FloodingMachines.java | 12 +- .../lagpreventions/KeepStashLoaded.java | 96 +- .../aef/modules/lagpreventions/LeverSpam.java | 51 +- .../lagpreventions/NoShulkerDrops.java | 21 +- .../lagpreventions/StashExplosions.java | 34 +- .../agelimits/CustomAgeLimits.java | 33 +- .../agelimits/ProjectileAgeLimit.java | 61 +- .../regionalactivity/BlockFormOrGrow.java | 24 +- .../regionalactivity/BlockPhysics.java | 22 +- .../regionalactivity/EntitySpawns.java | 21 +- .../regionalactivity/EntityTargeting.java | 38 +- .../regionalactivity/Explosions.java | 21 +- .../regionalactivity/LiquidSpread.java | 25 +- .../regionalactivity/Noteblocks.java | 40 - .../regionalactivity/Pathfinding.java | 27 +- .../regionalactivity/Pistons.java | 24 +- .../regionalactivity/Redstone.java | 24 +- .../RegionalActivityModule.java | 130 +- .../RegionalBlockActivityModule.java | 93 + .../RegionalEntityActivityModule.java | 93 + .../regionalactivity/SculkActivity.java | 79 - .../regionalactivity/SculkBloom.java | 36 +- .../aef/modules/misc/AutoBedOrSpigot5988.java | 30 +- .../aef/modules/misc/FirstJoinMessages.java | 22 +- .../aef/modules/misc/JoinLeaveMessages.java | 31 +- .../aef/modules/misc/MaskKickMessages.java | 7 +- .../aef/modules/misc/PreventMessageKick.java | 7 +- .../xginko/aef/modules/packets/BedTrap.java | 138 + .../modules/packets/BeehiveCoordinates.java | 10 +- .../aef/modules/packets/BigMessages.java | 51 + .../aef/modules/packets/InventoryLag.java | 26 +- .../aef/modules/packets/MapCursorLag.java | 27 +- .../aef/modules/packets/PacketModule.java | 19 +- .../modules/packets/PurpurBeehiveCrash.java | 8 +- .../aef/modules/packets/SequenceCrash.java | 5 +- .../xginko/aef/modules/packets/SignLag.java | 38 +- .../aef/modules/packets/TabCompleteCrash.java | 17 +- .../aef/modules/packets/WindowClickCrash.java | 9 +- .../xginko/aef/modules/patches/GodMode.java | 8 +- .../{BookBan.java => ItemDataBan.java} | 50 +- .../aef/modules/patches/PearlPhase.java | 141 - .../modules/patches/TeleportCoordExploit.java | 10 +- .../aef/modules/patches/WorldChangeCrash.java | 25 +- .../patches/commandsign/CommandSign.java | 8 +- .../aef/modules/preventions/BedTrap.java | 90 - .../modules/preventions/IllegalGameMode.java | 115 + ...edPlayers.java => IllegalPermissions.java} | 34 +- .../aef/modules/preventions/NetherRoof.java | 61 +- .../preventions/PreventNonSurvival.java | 83 - .../PistonExplodePermBlockRemoval.java | 11 +- ...stonPlaceWhileRetractPermBlockRemoval.java | 7 +- .../StructureGrowPermBlockRemoval.java | 8 +- .../portals/EndPortalDestruction.java | 15 +- .../portals/PreventAllEntitiesInPortals.java | 8 +- .../portals/PreventPortalTraps.java | 16 +- .../portals/PreventProjectilesInPortals.java | 9 +- .../PreventSpecificEntitiesInPortals.java | 23 +- .../withers/DisableWitherSkulls.java | 39 - .../withers/RateLimitWitherSkulls.java | 46 +- .../withers/RemoveAllSkullsPeriodically.java | 55 - .../withers/RemoveSkullsOnChunkload.java | 26 +- .../withers/RemoveSkullsOnChunkunload.java | 46 - .../withers/WitherSkullDropsAtSpawn.java | 63 + ...gAtSpawn.java => WitherSummonAtSpawn.java} | 41 +- .../java/me/xginko/aef/utils/KyoriUtil.java | 2 +- .../me/xginko/aef/utils/LocationUtil.java | 54 +- .../xginko/aef/{ => utils}/enums/AEFKey.java | 2 +- .../src/main/resources/config.yml | 2273 ----------------- .../src/main/resources/plugin.yml | 1 + AnarchyExploitFixesLegacy/build.gradle.kts | 1 - .../me/xginko/aef/AnarchyExploitFixes.java | 132 +- .../java/me/xginko/aef/commands/HelpCmd.java | 4 +- .../java/me/xginko/aef/commands/SayCmd.java | 4 +- .../aef/commands/ToggleConnectionMsgsCmd.java | 10 +- .../me/xginko/aef/commands/aef/AEFCmd.java | 51 +- .../aef/subcommands/DataValueSubCmd.java | 4 +- .../aef/subcommands/DisableSubCmd.java | 9 +- .../aef/subcommands/ElytraSubCmd.java | 4 +- .../aef/subcommands/GearedSubCmd.java | 4 +- .../commands/aef/subcommands/LagSubCmd.java | 10 +- .../aef/subcommands/ReloadSubCmd.java | 8 +- .../aef/subcommands/VersionSubCmd.java | 4 +- .../subcommands/bytesize/ByteSizeSubCmd.java | 7 +- .../subcommands/bytesize/InventorySubCmd.java | 6 +- .../aef/subcommands/bytesize/ItemSubCmd.java | 6 +- .../java/me/xginko/aef/config/Config.java | 13 +- .../java/me/xginko/aef/config/Datastore.java | 12 + .../me/xginko/aef/config/LanguageCache.java | 7 +- .../java/me/xginko/aef/modules/AEFModule.java | 98 +- .../bedrock/FillNetherCeilingOnChunkload.java | 15 +- .../bedrock/FillNetherFloorOnChunkload.java | 17 +- .../FillOverworldFloorOnChunkload.java | 17 +- .../PeriodicallyFillNetherCeiling.java | 19 +- .../bedrock/PeriodicallyFillNetherFloor.java | 17 +- .../PeriodicallyFillOverworldFloor.java | 19 +- .../PreventGoingBelowBedrockFloor.java | 25 +- .../modules/chat/PreventPluginScanning.java | 19 +- .../commandwhitelist/CommandWhitelist.java | 57 +- .../aef/modules/chunklimits/BlockLimit.java | 80 +- .../chunklimits/CustomEntityLimit.java | 27 +- .../modules/chunklimits/DroppedItemLimit.java | 41 +- .../modules/chunklimits/ExpBottleLimit.java | 90 - .../chunklimits/FallingBlockLimit.java | 35 +- .../modules/chunklimits/MinecartLimit.java | 16 +- .../chunklimits/NonLivingEntityLimit.java | 21 +- .../modules/chunklimits/ProjectileLimit.java | 134 + .../modules/chunklimits/TileEntityLimit.java | 26 +- .../aef/modules/chunklimits/VehicleLimit.java | 16 +- .../modules/chunklimits/VillagerLimit.java | 20 +- .../aef/modules/combat/AnchorAuraDelay.java | 101 - .../aef/modules/combat/BedAuraDelay.java | 100 - .../me/xginko/aef/modules/combat/BowBomb.java | 7 +- .../me/xginko/aef/modules/combat/Burrow.java | 19 +- .../aef/modules/combat/CrystalAuraDelay.java | 100 - .../xginko/aef/modules/combat/MultiTask.java | 7 +- .../modules/combat/PistonCrystalDelay.java | 32 +- .../xginko/aef/modules/combat/PistonPush.java | 7 +- .../aef/modules/combat/PortalGodMode.java | 32 +- .../aef/modules/combat/SilentSwapDelay.java | 37 +- .../modules/combat/auras/AnchorAuraDelay.java | 52 + .../modules/combat/auras/AuraDelayModule.java | 81 + .../modules/combat/auras/BedAuraDelay.java | 51 + .../combat/auras/CrystalAuraDelay.java | 51 + .../modules/dupepreventions/AllayDupe.java | 50 + .../dupepreventions/BookTitleDupe.java | 77 + .../ChestedEntitiesInPortals.java | 12 +- .../dupepreventions/ChestsOnEntities.java | 8 +- .../CloseEntityInventoriesOnLogout.java | 8 +- .../CloseEntityInventoryOnChunkUnload.java | 8 +- .../{patches => dupepreventions}/CowDupe.java | 16 +- .../dupepreventions/EndPortalDupe.java | 28 +- .../aef/modules/elytra/ElytraAtSpawn.java | 15 +- .../aef/modules/elytra/ElytraGlobal.java | 21 +- .../aef/modules/elytra/ElytraHelper.java | 41 +- .../aef/modules/elytra/ElytraOnCeiling.java | 18 +- .../aef/modules/elytra/ElytraPacketFly.java | 23 +- .../illegals/items/BannedItemNames.java | 26 +- .../illegals/items/BannedMaterials.java | 20 +- .../illegals/items/IllegalItemModule.java | 151 +- .../illegals/items/IllegalPotions.java | 22 +- .../illegals/items/InvalidStackSize.java | 20 +- .../modules/illegals/items/PlayerHeads.java | 18 +- .../aef/modules/illegals/items/SpawnEggs.java | 20 +- .../modules/illegals/items/Unbreakables.java | 33 +- .../items/datavalues/CustomDataValues.java | 24 +- .../items/datavalues/IllegalGoldenApples.java | 27 +- .../items/enchantments/HigherEnchants.java | 43 +- .../enchantments/InapplicableEnchants.java | 31 +- .../enchantments/IncompatibleEnchants.java | 129 +- .../illegals/items/nbt/CommandItems.java | 17 +- .../illegals/items/nbt/CustomNBTFilter.java | 27 +- .../items/nbt/NBTFilledStorageItem.java | 20 +- .../PeriodicallyRemoveIllegalBlocks.java | 47 +- .../RemoveIllegalBlocksOnChunkload.java | 53 +- .../placedblocks/RemoveUnnaturalSpawners.java | 81 +- .../lagpreventions/DisableCustomEntities.java | 71 + .../lagpreventions/FloodingMachines.java | 10 +- .../lagpreventions/KeepStashLoaded.java | 87 +- .../aef/modules/lagpreventions/LeverSpam.java | 54 +- .../lagpreventions/NoShulkerDrops.java | 19 +- .../lagpreventions/StashExplosions.java | 38 +- .../agelimits/CustomAgeLimits.java | 18 +- .../agelimits/ProjectileAgeLimit.java | 44 +- .../regionalactivity/BlockFormOrGrow.java | 45 +- .../regionalactivity/BlockPhysics.java | 41 +- .../regionalactivity/EntitySpawns.java | 22 +- .../regionalactivity/EntityTargeting.java | 38 +- .../regionalactivity/Explosions.java | 32 +- .../regionalactivity/LiquidSpread.java | 38 +- .../regionalactivity/Noteblocks.java | 40 - .../regionalactivity/Pathfinding.java | 27 +- .../regionalactivity/Pistons.java | 35 +- .../regionalactivity/Redstone.java | 37 +- .../RegionalActivityModule.java | 131 +- .../RegionalBlockActivityModule.java | 93 + .../RegionalEntityActivityModule.java | 93 + .../regionalactivity/SculkActivity.java | 79 - .../aef/modules/misc/FirstJoinMessages.java | 20 +- .../aef/modules/misc/JoinLeaveMessages.java | 22 +- .../aef/modules/misc/MaskKickMessages.java | 7 +- .../aef/modules/misc/PreventMessageKick.java | 7 +- .../modules/packets/BeehiveCoordinates.java | 10 +- .../aef/modules/packets/BigMessages.java | 51 + .../modules/packets/CraftingRecipeLag.java | 33 +- .../aef/modules/packets/InventoryLag.java | 50 +- .../aef/modules/packets/LecternCrash.java | 7 +- .../aef/modules/packets/MapCursorLag.java | 15 +- .../aef/modules/packets/NoComExploit.java | 9 +- .../aef/modules/packets/PacketModule.java | 19 +- .../modules/packets/PurpurBeehiveCrash.java | 7 +- .../aef/modules/packets/SequenceCrash.java | 5 +- .../xginko/aef/modules/packets/SignLag.java | 38 +- .../aef/modules/packets/TabCompleteCrash.java | 17 +- .../aef/modules/packets/WindowClickCrash.java | 8 +- .../xginko/aef/modules/patches/GodMode.java | 8 +- .../{BookBan.java => ItemDataBan.java} | 52 +- .../aef/modules/patches/PearlPhase.java | 109 - .../modules/patches/TeleportCoordExploit.java | 14 +- .../patches/commandsign/CommandSign.java | 18 +- .../patches/crashexploits/DispenserCrash.java | 10 +- .../crashexploits/EndGatewayCrash.java | 8 +- .../crashexploits/MultipleEnderdragons.java | 7 +- .../RedstoneOnTrapdoorCrash.java | 47 +- .../crashexploits/WorldChangeCrash.java | 27 +- .../aef/modules/preventions/BedTrap.java | 42 +- .../aef/modules/preventions/DisableFish.java | 63 - .../modules/preventions/IllegalGameMode.java | 122 + ...edPlayers.java => IllegalPermissions.java} | 36 +- .../aef/modules/preventions/MapSpam.java | 30 +- .../aef/modules/preventions/NetherRoof.java | 60 +- .../preventions/PreventNonSurvival.java | 88 - .../PistonExplodePermBlockRemoval.java | 11 +- ...stonPlaceWhileRetractPermBlockRemoval.java | 7 +- .../StructureGrowPermBlockRemoval.java | 8 +- .../portals/EndPortalDestruction.java | 15 +- .../portals/PreventAllEntitiesInPortals.java | 9 +- .../portals/PreventPortalTraps.java | 12 +- .../portals/PreventProjectilesInPortals.java | 9 +- .../PreventSpecificEntitiesInPortals.java | 26 +- .../withers/DisableWitherSkulls.java | 39 - .../withers/RateLimitWitherSkulls.java | 47 +- .../withers/RemoveAllSkullsPeriodically.java | 42 - ...ad.java => RemoveSkullsOnChunkUnload.java} | 28 +- .../withers/RemoveSkullsOnChunkload.java | 46 - .../withers/WitherSkullDropsAtSpawn.java | 63 + ...gAtSpawn.java => WitherSummonAtSpawn.java} | 40 +- .../me/xginko/aef/utils/LocationUtil.java | 54 +- .../java/me/xginko/aef/utils/WorldUtil.java | 2 +- .../src/main/resources/config.yml | 2056 --------------- .../src/main/resources/plugin.yml | 1 + .../kotlin/me.xginko.aef.wrapper.gradle.kts | 10 +- gradle/libs.versions.toml | 14 +- shared/build.gradle.kts | 1 + .../CWCommandSendListener.java | 2 +- .../commandsign/SignCommandListener.java | 5 +- .../java/me/xginko/aef/utils/BlockUtil.java | 12 +- .../me/xginko/aef/utils/CachingPermTool.java | 62 - .../java/me/xginko/aef/utils/ChunkUtil.java | 22 +- .../java/me/xginko/aef/utils/CommandUtil.java | 2 +- .../java/me/xginko/aef/utils/EntityUtil.java | 20 +- .../java/me/xginko/aef/utils/GenericUtil.java | 21 + .../java/me/xginko/aef/utils/ItemUtil.java | 4 +- .../me/xginko/aef/utils/MaterialUtil.java | 46 +- .../me/xginko/aef/utils/PlatformUtil.java | 36 +- .../{ => utils}/enums/IllegalHandling.java | 2 +- .../aef/{ => utils}/enums/ItemLegality.java | 2 +- .../me/xginko/aef/utils/enums/TriState.java | 28 + .../xginko/aef/utils/models/ExpiringSet.java | 260 +- .../java/me/xginko/aef/utils/models/Lazy.java | 35 + .../permissions}/AEFPermission.java | 28 +- .../permissions/BukkitPermissionHandler.java | 85 + .../LuckPermsPermissionHandler.java | 51 + .../utils/permissions/PermissionHandler.java | 26 + .../aef/utils/tickdata/SpigotReflection.java | 4 +- 335 files changed, 5897 insertions(+), 9849 deletions(-) delete mode 100644 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/events/PacketPlayerRespawnEvent.java delete mode 100644 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/listeners/AEFListener.java delete mode 100644 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/listeners/PacketPlayerRespawnListener.java delete mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/ExpBottleLimit.java create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/ProjectileLimit.java create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/AllayDupe.java create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BookTitleDupe.java create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/DisableCustomEntities.java delete mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Noteblocks.java create mode 100644 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalBlockActivityModule.java create mode 100644 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalEntityActivityModule.java delete mode 100644 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkActivity.java create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BedTrap.java create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BigMessages.java rename AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/{BookBan.java => ItemDataBan.java} (78%) delete mode 100644 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/PearlPhase.java delete mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/BedTrap.java create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/IllegalGameMode.java rename AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/{PreventOppedPlayers.java => IllegalPermissions.java} (59%) delete mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/PreventNonSurvival.java delete mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/DisableWitherSkulls.java delete mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveAllSkullsPeriodically.java delete mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkunload.java create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSkullDropsAtSpawn.java rename AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/{WitherSpawningAtSpawn.java => WitherSummonAtSpawn.java} (64%) rename AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/{ => utils}/enums/AEFKey.java (93%) delete mode 100644 AnarchyExploitFixesFolia/src/main/resources/config.yml delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/ExpBottleLimit.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/ProjectileLimit.java delete mode 100644 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/AnchorAuraDelay.java delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/BedAuraDelay.java delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/CrystalAuraDelay.java create mode 100644 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java create mode 100644 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/BedAuraDelay.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/AllayDupe.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BookTitleDupe.java rename AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/{patches => dupepreventions}/CowDupe.java (75%) create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/DisableCustomEntities.java delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Noteblocks.java create mode 100644 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalBlockActivityModule.java create mode 100644 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalEntityActivityModule.java delete mode 100644 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkActivity.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/BigMessages.java rename AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/{BookBan.java => ItemDataBan.java} (78%) delete mode 100644 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/PearlPhase.java delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/DisableFish.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/IllegalGameMode.java rename AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/{PreventOppedPlayers.java => IllegalPermissions.java} (57%) delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/PreventNonSurvival.java delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/DisableWitherSkulls.java delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveAllSkullsPeriodically.java rename AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/{RemoveSkullsOnChunkunload.java => RemoveSkullsOnChunkUnload.java} (55%) delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkload.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSkullDropsAtSpawn.java rename AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/{WitherSpawningAtSpawn.java => WitherSummonAtSpawn.java} (63%) delete mode 100644 AnarchyExploitFixesLegacy/src/main/resources/config.yml delete mode 100644 shared/src/main/java/me/xginko/aef/utils/CachingPermTool.java create mode 100644 shared/src/main/java/me/xginko/aef/utils/GenericUtil.java rename shared/src/main/java/me/xginko/aef/{ => utils}/enums/IllegalHandling.java (92%) rename shared/src/main/java/me/xginko/aef/{ => utils}/enums/ItemLegality.java (68%) create mode 100644 shared/src/main/java/me/xginko/aef/utils/enums/TriState.java create mode 100644 shared/src/main/java/me/xginko/aef/utils/models/Lazy.java rename shared/src/main/java/me/xginko/aef/{enums => utils/permissions}/AEFPermission.java (88%) create mode 100644 shared/src/main/java/me/xginko/aef/utils/permissions/BukkitPermissionHandler.java create mode 100644 shared/src/main/java/me/xginko/aef/utils/permissions/LuckPermsPermissionHandler.java create mode 100644 shared/src/main/java/me/xginko/aef/utils/permissions/PermissionHandler.java diff --git a/AnarchyExploitFixesFolia/build.gradle.kts b/AnarchyExploitFixesFolia/build.gradle.kts index 389677fa0..1af7ff82a 100755 --- a/AnarchyExploitFixesFolia/build.gradle.kts +++ b/AnarchyExploitFixesFolia/build.gradle.kts @@ -27,7 +27,6 @@ tasks.shadowJar { archiveFileName = "${rootProject.name}-${project.name}-${project.version}.${archiveExtension.get()}" exclude( "com/cryptomorin/xseries/XBiome*", - "com/cryptomorin/xseries/XPotion*", "com/cryptomorin/xseries/NMSExtras*", "com/cryptomorin/xseries/NoteBlockMusic*", "com/cryptomorin/xseries/SkullCacheListener*" diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index c3da0514c..24668dea1 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -1,14 +1,14 @@ package me.xginko.aef; import com.github.retrooper.packetevents.PacketEvents; -import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import de.tr7zw.changeme.nbtapi.NBT; import me.xginko.aef.commands.AEFCommand; import me.xginko.aef.config.Config; import me.xginko.aef.config.LanguageCache; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.listeners.AEFListener; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.permissions.PermissionHandler; import me.xginko.aef.utils.KyoriUtil; import me.xginko.aef.utils.PlatformUtil; import me.xginko.aef.utils.tickdata.TickReporter; @@ -24,8 +24,6 @@ import java.io.File; import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.util.Arrays; import java.util.Collections; @@ -34,6 +32,7 @@ import java.util.Locale; import java.util.Map; import java.util.jar.JarFile; +import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -45,31 +44,33 @@ public final class AnarchyExploitFixes extends JavaPlugin { private static AnarchyExploitFixes instance; private static Map languageCacheMap; private static Config config; + private static TickReporter tickReporter; - private static CachingPermTool cachingPermTool; + private static PermissionHandler permissionHandler; private static ComponentLogger prefixedLogger, unPrefixedLogger; + private static Metrics metrics; private static boolean isPacketEventsInstalled; @Override public void onLoad() { PlatformUtil.load(); - prefixedLogger = ComponentLogger.logger(getLogger().getName()); - unPrefixedLogger = ComponentLogger.logger(""); - // Disable logging for some shaded libraries as those can get very verbose - String shadedLibs = getClass().getPackageName() + ".libs"; - Configurator.setLevel(shadedLibs + ".reflections.Reflections", Level.OFF); - isPacketEventsInstalled = getServer().getPluginManager().getPlugin("packetevents") != null; - if (isPacketEventsInstalled) { - // Configure and load packetevents - PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this)); - PacketEvents.getAPI().getSettings().kickOnPacketException(true).reEncodeByDefault(false).checkForUpdates(false); - PacketEvents.getAPI().load(); - } + // Disable info logging for Reflections because it does not provide additional value to the user and makes startup log look ugly. + Configurator.setLevel(AnarchyExploitFixes.class.getPackage().getName() + ".libs.reflections.Reflections", Level.WARN); } @Override public void onEnable() { + if (!PlatformUtil.isPaper()) { + getLogger().severe("This plugin depends on Paper's API, which is not present on your server."); + getServer().getPluginManager().disablePlugin(this); + return; + } + + prefixedLogger = ComponentLogger.logger(getLogger().getName()); + unPrefixedLogger = ComponentLogger.logger(""); + + isPacketEventsInstalled = getServer().getPluginManager().getPlugin("packetevents") != null; if (!isPacketEventsInstalled) { Stream.of(" ", " _ _ _ _ _ ", @@ -89,10 +90,6 @@ public void onEnable() { return; } - instance = this; - cachingPermTool = CachingPermTool.enable(this); - metrics = new Metrics(this, 8700); - Stream.of(" ", " ", " █████ ███████ ███████ ", @@ -104,32 +101,29 @@ public void onEnable() { " " ).map(str -> Component.text(str).color(KyoriUtil.AEF_WHITE)).forEach(prefixedLogger::info); - if (!PlatformUtil.isPaper()) { - prefixedLogger.error("This plugin depends on Paper's API, which is not present on your server."); + ServerVersion serverVersion = PacketEvents.getAPI().getServerManager().getVersion(); + prefixedLogger.info("Detected {} {}", PlatformUtil.getServerType().niceName(), + serverVersion.name().replace("V_", "").replace('_', '.')); + if (serverVersion.isOlderThanOrEquals(ServerVersion.V_1_19_3) || + serverVersion.equals(ServerVersion.V_1_19_4) && !PlatformUtil.isFolia()) { + prefixedLogger.error("This plugin jar is incompatible with your Server. Please use the Legacy jar."); getServer().getPluginManager().disablePlugin(this); return; } - prefixedLogger.info("Detected Version 1.{}.{}", PlatformUtil.getMinecraftVersion(), PlatformUtil.getMinecraftPatchVersion()); - - if (PlatformUtil.getMinecraftVersion() < 19) { - prefixedLogger.error("The Folia jar is intended for Paper and Folia servers running 1.19 and above."); - prefixedLogger.error("Please replace it with the Legacy jar."); + try { + Files.createDirectories(getDataFolder().toPath()); + } catch (Exception e) { + prefixedLogger.error("Unable to create plugin directory.", e); getServer().getPluginManager().disablePlugin(this); return; } - if (PlatformUtil.isFolia()) { - prefixedLogger.info("Detected Folia server."); - } + instance = this; - try { - createDirectory(getDataFolder()); - } catch (IOException e) { - prefixedLogger.error("Unable to create plugin folder!", e); - getServer().getPluginManager().disablePlugin(this); - return; - } + prefixedLogger.info("Registering Permissions"); + permissionHandler = PermissionHandler.create(this); + AEFPermission.registerAll(); prefixedLogger.info("Loading Config"); reloadConfiguration(); @@ -140,31 +134,30 @@ public void onEnable() { prefixedLogger.info("Registering Commands"); AEFCommand.registerCommands(); - prefixedLogger.info("Registering Permissions"); - AEFPermission.registerPermissions(); + prefixedLogger.info("Loading NBT-API"); + // Hide all messages with a log level lower than WARNING because of the same reason as Reflections logging. + Logger.getLogger("NBTAPI").setLevel(java.util.logging.Level.WARNING); + if (!NBT.preloadApi()) prefixedLogger.error("Error initializing NBT-API! This will break some modules!"); - prefixedLogger.info("Initializing PacketEvents"); - PacketEvents.getAPI().init(); + prefixedLogger.info("Loading Metrics"); + metrics = new Metrics(this, 8700); - prefixedLogger.info("Ready."); + prefixedLogger.info("Done."); } @Override public void onDisable() { + AEFPermission.unregisterAll(); if (isPacketEventsInstalled) { - AEFModule.ENABLED_MODULES.forEach(AEFModule::disable); - AEFModule.ENABLED_MODULES.clear(); - AEFListener.LISTENERS.forEach(AEFListener::disable); - AEFListener.LISTENERS.clear(); - PacketEvents.getAPI().terminate(); + AEFModule.disableAll(); } if (languageCacheMap != null) { languageCacheMap.clear(); languageCacheMap = null; } - if (cachingPermTool != null) { - cachingPermTool.disable(); - cachingPermTool = null; + if (permissionHandler != null) { + permissionHandler.disable(); + permissionHandler = null; } if (tickReporter != null) { tickReporter.disable(); @@ -184,7 +177,11 @@ public static AnarchyExploitFixes getInstance() { return instance; } - public static TickReporter getTickReporter() { + public static PermissionHandler permissions() { + return permissionHandler; + } + + public static TickReporter tickReporter() { return tickReporter; } @@ -192,11 +189,11 @@ public static Config config() { return config; } - public static ComponentLogger getPrefixedLogger() { + public static ComponentLogger prefixedLogger() { return prefixedLogger; } - public static ComponentLogger getUnprefixedLogger() { + public static ComponentLogger unprefixedLogger() { return unPrefixedLogger; } @@ -213,14 +210,6 @@ public static LanguageCache getLang(String lang) { return languageCacheMap.getOrDefault(lang.replace("-", "_"), languageCacheMap.get(config.default_lang.toString().toLowerCase())); } - public void createDirectory(File dir) throws IOException { - try { - Files.createDirectories(dir.toPath()); - } catch (FileAlreadyExistsException e) { // Thrown if dir exists but is not a directory - if (dir.delete()) createDirectory(dir); - } - } - public void reloadPlugin() { reloadConfiguration(); reloadLang(); @@ -228,11 +217,9 @@ public void reloadPlugin() { private void reloadConfiguration() { try { - createDirectory(getDataFolder()); config = new Config(); if (tickReporter != null) tickReporter.disable(); tickReporter = TickReporter.create(this, config.tickData_cache_duration); - AEFListener.reloadListeners(); AEFModule.reloadModules(); config.saveConfig(); } catch (Throwable t) { @@ -276,10 +263,9 @@ public void reloadLang() { private @NotNull List getAvailableTranslations() { try (final JarFile pluginJar = new JarFile(getFile())) { - createDirectory(new File(getDataFolder(), "/lang")); final Pattern langPattern = Pattern.compile("([a-z]{1,3}_[a-z]{1,3})(\\.yml)", Pattern.CASE_INSENSITIVE); - final File[] langDirFiles = new File(getDataFolder() + "/lang").listFiles(); - return Stream.concat(pluginJar.stream().map(ZipEntry::getName), Arrays.stream(langDirFiles).map(File::getName)) + final File langFolder = new File(getDataFolder(), "/lang"); + return (langFolder.exists() ? Arrays.stream(langFolder.listFiles()).map(File::getName) : pluginJar.stream().map(ZipEntry::getName)) .map(langPattern::matcher) .filter(Matcher::find) .map(matcher -> matcher.group(1)) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java index 1e12595ae..12920da9c 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java @@ -1,7 +1,7 @@ package me.xginko.aef.commands; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; @@ -37,7 +37,7 @@ public void enable() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_HELP.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_HELP.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java index 1873c8e09..41017fa07 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java @@ -1,7 +1,7 @@ package me.xginko.aef.commands; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.CommandUtil; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.minimessage.MiniMessage; @@ -40,7 +40,7 @@ public void enable() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_SAY.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_SAY.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java index bc769562d..dda8ef895 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java @@ -1,8 +1,8 @@ package me.xginko.aef.commands; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFKey; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.enums.AEFKey; +import me.xginko.aef.utils.permissions.AEFPermission; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.command.Command; @@ -44,7 +44,7 @@ public void enable() { @Override @SuppressWarnings("DataFlowIssue") public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_TOGGLE_CONNECT_MSGS.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_TOGGLE_CONNECT_MSGS.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java index 6e3b87525..70325fa00 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java @@ -1,5 +1,7 @@ package me.xginko.aef.commands.aef; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.AEFCommand; import me.xginko.aef.commands.SubCommand; @@ -18,11 +20,14 @@ import java.util.Collections; import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; public class AEFCmd extends Command implements AEFCommand { - private final @NotNull List subCommands; + private final @NotNull Set subCommands; private final @NotNull List tabCompletes; private final @NotNull List overview; @@ -46,16 +51,17 @@ public AEFCmd() { " <#00edff>/aef bytesize (player) (utf8/utf16)", " <#869699>- <#e2fdff>Get the byte size of an item or inventory.", "" - ).map(MiniMessage.miniMessage()::deserialize).toList(); - this.subCommands = List.of( + ).map(MiniMessage.miniMessage()::deserialize) + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf)); + this.subCommands = ImmutableSet.of( new ReloadSubCmd(), new VersionSubCmd(), new DisableSubCmd(), new LagSubCmd(), new ElytraSubCmd(), - new GearedSubCmd() - ); - this.tabCompletes = subCommands.stream().map(SubCommand::label).sorted().toList(); + new GearedSubCmd()); + this.tabCompletes = subCommands.stream().map(SubCommand::label).sorted() + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf)); } @Override @@ -75,7 +81,9 @@ public void enable() { throws CommandException, IllegalArgumentException { if (args.length == 1) { - return tabCompletes; + return tabCompletes.stream() + .filter(cmd -> cmd.toLowerCase(Locale.ROOT).startsWith(args[0].toLowerCase(Locale.ROOT))) + .collect(Collectors.toList()); } if (args.length > 1) { @@ -84,8 +92,6 @@ public void enable() { return subCommand.tabComplete(sender, alias, args); } } - - return tabCompletes.stream().filter(cmd -> cmd.startsWith(args[0])).toList(); } return Collections.emptyList(); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/DisableSubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/DisableSubCmd.java index 36e23550c..b5b7f3f74 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/DisableSubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/DisableSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.KyoriUtil; import net.kyori.adventure.text.Component; @@ -29,7 +29,7 @@ public class DisableSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_DISABLE.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_DISABLE.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } @@ -37,8 +37,8 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLab sender.sendMessage(Component.empty()); sender.sendMessage(Component.text(" Disabling plugin.").color(KyoriUtil.AEF_WHITE)); AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getGlobalRegionScheduler().execute(plugin, () -> { - AEFModule.ENABLED_MODULES.forEach(AEFModule::disable); + plugin.getServer().getAsyncScheduler().runNow(plugin, disable -> { + AEFModule.disableAll(); sender.sendMessage(Component.text(" All enabled plugin features have been disabled.").color(KyoriUtil.AEF_BLUE)); sender.sendMessage(Component.text(" Use /aef reload to enable the plugin again.").color(KyoriUtil.AEF_BLUE)); sender.sendMessage(Component.empty()); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/ElytraSubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/ElytraSubCmd.java index d695e883f..d7d9039df 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/ElytraSubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/ElytraSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.KyoriUtil; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; @@ -31,7 +31,7 @@ public class ElytraSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_ELYTRA.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_ELYTRA.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/GearedSubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/GearedSubCmd.java index 636de0c29..b9e239288 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/GearedSubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/GearedSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.KyoriUtil; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; @@ -33,7 +33,7 @@ public class GearedSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_GEARED.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_GEARED.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/LagSubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/LagSubCmd.java index da2fdaa72..a78724f77 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/LagSubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/LagSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.KyoriUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -31,12 +31,16 @@ public LagSubCmd() { public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException { - return args.length == 2 && sender.hasPermission(AEFPermission.CMD_AEF_LAG.bukkit()) ? tabCompletes : Collections.emptyList(); + if (args.length == 2 && AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_LAG.node()).toBoolean()) { + return tabCompletes; + } + + return Collections.emptyList(); } @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_LAG.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_LAG.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } @@ -60,7 +64,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLab } catch (InterruptedException e) { sender.sendMessage(Component.text(" Operation was interrupted! - " + e.getLocalizedMessage()).color(NamedTextColor.RED)); player.sendMessage(Component.empty()); - AnarchyExploitFixes.getPrefixedLogger().error("Lag command encountered an error!", e); + AnarchyExploitFixes.prefixedLogger().error("Lag command encountered an error!", e); } }, null, 1L); } else { @@ -72,7 +76,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLab sender.sendMessage(Component.empty()); } catch (InterruptedException e) { sender.sendMessage(Component.text(" Operation was interrupted! - " + e.getLocalizedMessage()).color(NamedTextColor.RED)); - AnarchyExploitFixes.getPrefixedLogger().error("Lag command encountered an error!", e); + AnarchyExploitFixes.prefixedLogger().error("Lag command encountered an error!", e); } }); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/ReloadSubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/ReloadSubCmd.java index c13653a82..c512c8565 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/ReloadSubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/ReloadSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.KyoriUtil; import net.kyori.adventure.text.Component; import org.bukkit.command.CommandException; @@ -28,7 +28,7 @@ public class ReloadSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_RELOAD.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_RELOAD.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } @@ -36,7 +36,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLab sender.sendMessage(Component.empty()); sender.sendMessage(Component.text(" Reloading AnarchyExploitFixes...").color(KyoriUtil.AEF_WHITE)); AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getGlobalRegionScheduler().execute(plugin, () -> { + plugin.getServer().getAsyncScheduler().runNow(plugin, reload -> { plugin.reloadPlugin(); sender.sendMessage(Component.text(" Reload complete.").color(KyoriUtil.AEF_BLUE)); sender.sendMessage(Component.empty()); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/VersionSubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/VersionSubCmd.java index cdcf19bd8..f1d7fa892 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/VersionSubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/VersionSubCmd.java @@ -3,7 +3,7 @@ import io.papermc.paper.plugin.configuration.PluginMeta; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.KyoriUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; @@ -32,7 +32,7 @@ public class VersionSubCmd extends SubCommand { @Override @SuppressWarnings({"UnstableApiUsage", "DataFlowIssue"}) public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_VERSION.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_VERSION.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ByteSizeSubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ByteSizeSubCmd.java index 2dc889734..f3f9cd4f7 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ByteSizeSubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ByteSizeSubCmd.java @@ -1,11 +1,11 @@ package me.xginko.aef.commands.aef.subcommands.bytesize; +import com.google.common.collect.ImmutableList; import me.xginko.aef.commands.SubCommand; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -16,8 +16,9 @@ public class ByteSizeSubCmd extends SubCommand { private final List tabCompletes; public ByteSizeSubCmd() { - this.subCommands = Arrays.asList(new InventorySubCmd(), new ItemSubCmd()); - this.tabCompletes = subCommands.stream().map(SubCommand::label).collect(Collectors.toList()); + this.subCommands = ImmutableList.of(new InventorySubCmd(), new ItemSubCmd()); + this.tabCompletes = subCommands.stream().map(SubCommand::label) + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf)); } @Override diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/InventorySubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/InventorySubCmd.java index 64fa435b0..939e0d247 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/InventorySubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/InventorySubCmd.java @@ -4,7 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.KyoriUtil; import net.kyori.adventure.text.Component; @@ -40,7 +40,7 @@ public InventorySubCmd() { public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException { - if (!sender.hasPermission(AEFPermission.CMD_AEF_SIZE_INV.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_SIZE_INV.node()).toBoolean()) { return Collections.emptyList(); } @@ -63,7 +63,7 @@ public InventorySubCmd() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_SIZE_INV.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_SIZE_INV.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ItemSubCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ItemSubCmd.java index 0c439947b..72ffe231b 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ItemSubCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ItemSubCmd.java @@ -4,7 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.KyoriUtil; import net.kyori.adventure.text.Component; @@ -40,7 +40,7 @@ public ItemSubCmd() { public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException { - if (!sender.hasPermission(AEFPermission.CMD_AEF_SIZE_HAND.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_SIZE_HAND.node()).toBoolean()) { return Collections.emptyList(); } @@ -63,7 +63,7 @@ public ItemSubCmd() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_SIZE_HAND.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_SIZE_HAND.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/config/Config.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/config/Config.java index 20d2716ae..990dfab9e 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/config/Config.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/config/Config.java @@ -32,6 +32,7 @@ public Config() throws Exception { AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); // Load config.yml with ConfigMaster this.config = ConfigFile.loadConfig(new File(plugin.getDataFolder(), "config.yml")); + config.set("plugin-version", plugin.getPluginMeta().getVersion()); config.set("server-version", plugin.getServer().getVersion()); @@ -87,7 +88,7 @@ The time in ticks (1 sec = 20 ticks) a checked tps will be cached\s try { parsedSound = Sound.valueOf(configuredSound); } catch (IllegalArgumentException e) { - AnarchyExploitFixes.getPrefixedLogger().warn(" Sound '{}' does not exist. Using default.", configuredSound); + AnarchyExploitFixes.prefixedLogger().warn(" Sound '{}' does not exist. Using default.", configuredSound); parsedSound = Sound.ENTITY_EXPERIENCE_ORB_PICKUP; } this.elytra_too_fast_sound = parsedSound; @@ -112,7 +113,7 @@ public void saveConfig() { try { config.save(); } catch (Exception e) { - AnarchyExploitFixes.getPrefixedLogger().error("Failed to save config file!", e); + AnarchyExploitFixes.prefixedLogger().error("Failed to save config file!", e); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/config/LanguageCache.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/config/LanguageCache.java index 8d1cec9f5..984c9b0d4 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/config/LanguageCache.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/config/LanguageCache.java @@ -7,6 +7,7 @@ import net.kyori.adventure.text.minimessage.MiniMessage; import java.io.File; +import java.nio.file.Files; import java.util.List; import java.util.Locale; @@ -33,9 +34,9 @@ public LanguageCache(String langString) throws Exception { AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); File langYML = new File(plugin.getDataFolder() + "/lang", langString + ".yml"); // Check if the lang folder has already been created - File parent = langYML.getParentFile(); - if (!parent.exists() && !parent.mkdir()) - AnarchyExploitFixes.getPrefixedLogger().error("Unable to create lang directory."); + File langFolder = langYML.getParentFile(); + if (!langFolder.exists()) + Files.createDirectories(langFolder.toPath()); // Check if the file already exists and save the one from the plugin's resources folder if it does not if (!langYML.exists()) plugin.saveResource("lang/" + langString + ".yml", false); @@ -171,7 +172,7 @@ public LanguageCache(String langString) throws Exception { try { this.lang.save(); } catch (Exception e) { - AnarchyExploitFixes.getPrefixedLogger().error("Failed to save language file: {}!", langYML.getName(), e); + AnarchyExploitFixes.prefixedLogger().error("Failed to save language file: {}!", langYML.getName(), e); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/events/PacketPlayerRespawnEvent.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/events/PacketPlayerRespawnEvent.java deleted file mode 100644 index 4a20147e1..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/events/PacketPlayerRespawnEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -package me.xginko.aef.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; -import org.jetbrains.annotations.NotNull; - -public class PacketPlayerRespawnEvent extends Event { - - private static final @NotNull HandlerList handlers = new HandlerList(); - - private final @NotNull Player player; - - public PacketPlayerRespawnEvent(@NotNull Player player) { - super(false); - this.player = player; - } - - public @NotNull Player getPlayer() { - return player; - } - - public boolean isPotentialBedSpawn() { - if (player.getPotentialBedLocation() == null) - return false; - return player.getPotentialBedLocation().distanceSquared(player.getLocation()) <= 16; - } - - @Override - public @NotNull HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/listeners/AEFListener.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/listeners/AEFListener.java deleted file mode 100644 index 689af3099..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/listeners/AEFListener.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.xginko.aef.listeners; - -import com.github.retrooper.packetevents.event.PacketListenerAbstract; -import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.utils.models.ConditionalEnableable; -import me.xginko.aef.utils.models.Disableable; -import org.reflections.Reflections; -import org.reflections.scanners.Scanners; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.Set; - -public interface AEFListener extends ConditionalEnableable, Disableable { - - Reflections LISTENERS_PACKAGE = new Reflections(AEFListener.class.getPackage().getName()); - - Set LISTENERS = new HashSet<>(); - - static void reloadListeners() { - LISTENERS.forEach(AEFListener::disable); - LISTENERS.clear(); - - for (Class clazz : LISTENERS_PACKAGE.get(Scanners.SubTypes.of(AEFListener.class).asClass())) { - if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) continue; - - try { - AEFListener listener = (AEFListener) clazz.getDeclaredConstructor().newInstance(); - if (listener.shouldEnable()) { - if (listener instanceof PacketListenerAbstract && AnarchyExploitFixes.config().packets_disabled) { - AnarchyExploitFixes.getPrefixedLogger() - .warn("Cannot enable listener {} because you disabled packets in config!", clazz.getSimpleName()); - continue; - } - - listener.enable(); - LISTENERS.add(listener); - } - } catch (Throwable t) { - AnarchyExploitFixes.getPrefixedLogger().error("Failed to load listener {}", clazz.getSimpleName(), t); - } - } - } - -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/listeners/PacketPlayerRespawnListener.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/listeners/PacketPlayerRespawnListener.java deleted file mode 100644 index 26cf0856f..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/listeners/PacketPlayerRespawnListener.java +++ /dev/null @@ -1,73 +0,0 @@ -package me.xginko.aef.listeners; - -import com.github.retrooper.packetevents.PacketEvents; -import com.github.retrooper.packetevents.event.PacketListenerAbstract; -import com.github.retrooper.packetevents.event.PacketListenerPriority; -import com.github.retrooper.packetevents.event.PacketReceiveEvent; -import com.github.retrooper.packetevents.protocol.packettype.PacketType; -import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus; -import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.events.PacketPlayerRespawnEvent; -import me.xginko.aef.utils.PlatformUtil; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.PlayerDeathEvent; - -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CopyOnWriteArraySet; - -public class PacketPlayerRespawnListener extends PacketListenerAbstract implements AEFListener, Listener { - - private static final Set DEAD_PLAYERS = new CopyOnWriteArraySet<>(); - private final AnarchyExploitFixes plugin; - - public PacketPlayerRespawnListener() { - super(PacketListenerPriority.HIGHEST); - this.plugin = AnarchyExploitFixes.getInstance(); - } - - @Override - public boolean shouldEnable() { - return PlatformUtil.isFolia(); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - PacketEvents.getAPI().getEventManager().unregisterListener(this); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - PacketEvents.getAPI().getEventManager().registerListener(this); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerDeath(PlayerDeathEvent event) { - DEAD_PLAYERS.add(event.getPlayer().getUniqueId()); - } - - @Override - public void onPacketReceive(PacketReceiveEvent event) { - if (event.isCancelled()) return; - if (event.getPacketType() != PacketType.Play.Client.CLIENT_STATUS) return; - WrapperPlayClientClientStatus packet = new WrapperPlayClientClientStatus(event); - if (packet.getAction() != WrapperPlayClientClientStatus.Action.PERFORM_RESPAWN) return; - - UUID uuid = event.getUser().getUUID(); - Player bukkitPlayer = plugin.getServer().getPlayer(uuid); - if (bukkitPlayer == null) return; - - if (DEAD_PLAYERS.contains(uuid) || bukkitPlayer.isDead()) { - bukkitPlayer.getScheduler().execute(plugin, () -> { - new PacketPlayerRespawnEvent(bukkitPlayer).callEvent(); - DEAD_PLAYERS.remove(bukkitPlayer.getUniqueId()); - }, null, 20L); - } - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/AEFModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/AEFModule.java index dd77b19dd..fe3340792 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/AEFModule.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/AEFModule.java @@ -1,5 +1,6 @@ package me.xginko.aef.modules; +import com.google.common.collect.ImmutableSet; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.config.Config; import me.xginko.aef.modules.packets.PacketModule; @@ -9,70 +10,118 @@ import org.reflections.scanners.Scanners; import java.lang.reflect.Modifier; +import java.util.Comparator; import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; public abstract class AEFModule implements ConditionalEnableable, Disableable { - private static final Reflections MODULES_PACKAGE = new Reflections(AEFModule.class.getPackage().getName()); - public static final Set ENABLED_MODULES = new HashSet<>(); + protected static final Set> AVAILABLE_MODULES; + protected static final Set ENABLED_MODULES; - protected final AnarchyExploitFixes plugin; - protected final Config config; - public final String configPath; - private final String logFormat; + static { + AVAILABLE_MODULES = new Reflections(AEFModule.class.getPackage().getName()) + .get(Scanners.SubTypes.of(AEFModule.class).asClass()) + .stream() + .filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) + .map(clazz -> (Class) clazz) + .sorted(Comparator.comparing(Class::getSimpleName)) + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableSet::copyOf)); + ENABLED_MODULES = new HashSet<>(); + } + + protected final AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); + protected final Config config = AnarchyExploitFixes.config(); + protected final String configPath, logFormat; + protected final boolean configEnabled; - public AEFModule(String configPath) { - this.plugin = AnarchyExploitFixes.getInstance(); - this.config = AnarchyExploitFixes.config(); + public AEFModule(String configPath) { // Modules that should not automatically get an enable option this.configPath = configPath; - shouldEnable(); // Ensure enable option is always first - String[] paths = configPath.split("\\."); - if (paths.length <= 2) { - this.logFormat = "<" + configPath + "> {}"; + this.configEnabled = false; + this.logFormat = createLogFormat(configPath); + } + + public AEFModule(String configPath, boolean defEnabled) { + this(configPath, defEnabled, null); + } + + public AEFModule(String configPath, boolean defEnabled, String comment) { + this.configPath = configPath; + this.logFormat = createLogFormat(configPath); + if (comment == null || comment.isEmpty()) { + this.configEnabled = config.getBoolean(configPath + ".enable", defEnabled); } else { - this.logFormat = "<" + paths[paths.length - 2] + "." + paths[paths.length - 1] + "> {}"; + this.configEnabled = config.getBoolean(configPath + ".enable", defEnabled, comment); } } - public static void reloadModules() { - ENABLED_MODULES.forEach(AEFModule::disable); + private static String createLogFormat(String configPath) { + String[] paths = configPath.split("\\."); + return "<" + (paths.length < 3 ? configPath : paths[paths.length - 2] + "." + paths[paths.length - 1]) + "> {}"; + } + + public boolean shouldEnable() { + return configEnabled; + } + + public static void disableAll() { + for (AEFModule module : ENABLED_MODULES) { + try { + module.disable(); + } catch (Throwable t) { + module.error("Failed during disable. " + t.getLocalizedMessage()); + } + } ENABLED_MODULES.clear(); + } - for (Class clazz : MODULES_PACKAGE.get(Scanners.SubTypes.of(AEFModule.class).asClass())) { - if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) continue; + public static void reloadModules() { + disableAll(); + for (Class moduleClass : AVAILABLE_MODULES) { try { - AEFModule module = (AEFModule) clazz.getDeclaredConstructor().newInstance(); + AEFModule module = moduleClass.getDeclaredConstructor().newInstance(); if (module.shouldEnable()) { if (module instanceof PacketModule && AnarchyExploitFixes.config().packets_disabled) { module.warn("Cannot enable because you disabled packets in config!"); - continue; + } else { + ENABLED_MODULES.add(module); } - - module.enable(); - ENABLED_MODULES.add(module); } } catch (Throwable t) { - AnarchyExploitFixes.getPrefixedLogger().error("Failed to load module {}", clazz.getSimpleName(), t); + if (t.getCause() instanceof NoClassDefFoundError) { + AnarchyExploitFixes.prefixedLogger().info("Dependencies for module class {} missing, cannot enable.", moduleClass.getSimpleName()); + } else { + AnarchyExploitFixes.prefixedLogger().warn("Module class '{}' failed to init.", moduleClass.getSimpleName(), t); + } + } + } + + for (AEFModule module : ENABLED_MODULES) { + try { + module.enable(); + } catch (Throwable t) { + module.error("Failed during enable. " + t.getLocalizedMessage()); + try { module.disable(); } catch (Throwable ignored) {} } } } protected void error(String message, Throwable throwable) { - AnarchyExploitFixes.getPrefixedLogger().error(logFormat, message, throwable); + AnarchyExploitFixes.prefixedLogger().error(logFormat, message, throwable); } protected void error(String message) { - AnarchyExploitFixes.getPrefixedLogger().error(logFormat, message); + AnarchyExploitFixes.prefixedLogger().error(logFormat, message); } protected void warn(String message) { - AnarchyExploitFixes.getPrefixedLogger().warn(logFormat, message); + AnarchyExploitFixes.prefixedLogger().warn(logFormat, message); } protected void info(String message) { - AnarchyExploitFixes.getPrefixedLogger().info(logFormat, message); + AnarchyExploitFixes.prefixedLogger().info(logFormat, message); } protected void notRecognized(Class clazz, String unrecognized) { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillNetherCeilingOnChunkload.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillNetherCeilingOnChunkload.java index f94bf6b17..3b27ed755 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillNetherCeilingOnChunkload.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillNetherCeilingOnChunkload.java @@ -21,7 +21,7 @@ public class FillNetherCeilingOnChunkload extends AEFModule implements Listener private final boolean alsoCheckNewChunks, checkShouldPauseOnLowTPS; public FillNetherCeilingOnChunkload() { - super("bedrock.fill-in-bedrock.nether-ceiling.fill-on-chunkload"); + super("bedrock.fill-in-bedrock.nether-ceiling.fill-on-chunkload", false); this.alsoCheckNewChunks = config.getBoolean(configPath + ".also-check-new-chunks", false, """ Recommended to leave off. Only useful if world generation is broken."""); this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", @@ -37,11 +37,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -49,12 +44,12 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; if (!alsoCheckNewChunks && event.isNewChunk()) return; - World world = event.getWorld(); - if (world.getEnvironment() != World.Environment.NETHER) return; - if (exemptedWorlds.contains(world.getName())) return; + if (event.getWorld().getEnvironment() != World.Environment.NETHER) return; + if (exemptedWorlds.contains(event.getWorld().getName())) return; - if (!checkShouldPauseOnLowTPS || AnarchyExploitFixes.getTickReporter().getTPS() >= pauseTPS) { + if (!checkShouldPauseOnLowTPS || AnarchyExploitFixes.tickReporter().getTPS() >= pauseTPS) { ChunkUtil.createBedrockLayer(event.getChunk(), config.nether_ceiling_max_y); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillNetherFloorOnChunkload.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillNetherFloorOnChunkload.java index 211ed9860..7db1a64c7 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillNetherFloorOnChunkload.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillNetherFloorOnChunkload.java @@ -21,7 +21,7 @@ public class FillNetherFloorOnChunkload extends AEFModule implements Listener { private final boolean alsoCheckNewChunks, checkShouldPauseOnLowTPS; public FillNetherFloorOnChunkload() { - super("bedrock.fill-in-bedrock.nether-floor.fill-on-chunkload"); + super("bedrock.fill-in-bedrock.nether-floor.fill-on-chunkload", false); this.alsoCheckNewChunks = config.getBoolean(configPath + ".also-check-new-chunks", false, """ Recommended to leave off. Only useful if world generation is broken."""); this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", @@ -37,11 +37,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -49,13 +44,13 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; if (!alsoCheckNewChunks && event.isNewChunk()) return; - World world = event.getWorld(); - if (world.getEnvironment() != World.Environment.NETHER) return; - if (exemptedWorlds.contains(world.getName())) return; + if (event.getWorld().getEnvironment() != World.Environment.NETHER) return; + if (exemptedWorlds.contains(event.getWorld().getName())) return; - if (!checkShouldPauseOnLowTPS || AnarchyExploitFixes.getTickReporter().getTPS() >= pauseTPS) { - ChunkUtil.createBedrockLayer(event.getChunk(), world.getMinHeight()); + if (!checkShouldPauseOnLowTPS || AnarchyExploitFixes.tickReporter().getTPS() >= pauseTPS) { + ChunkUtil.createBedrockLayer(event.getChunk(), event.getWorld().getMinHeight()); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillOverworldFloorOnChunkload.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillOverworldFloorOnChunkload.java index 02379ee27..f91860a0b 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillOverworldFloorOnChunkload.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/FillOverworldFloorOnChunkload.java @@ -21,7 +21,7 @@ public class FillOverworldFloorOnChunkload extends AEFModule implements Listener private final boolean alsoCheckNewChunks, checkShouldPauseOnLowTPS; public FillOverworldFloorOnChunkload() { - super("bedrock.fill-in-bedrock.overworld-floor.fill-on-chunkload"); + super("bedrock.fill-in-bedrock.overworld-floor.fill-on-chunkload", false); this.alsoCheckNewChunks = config.getBoolean(configPath + ".also-check-new-chunks", false, """ Recommended to leave off. Only useful if world generation is broken."""); this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", @@ -37,11 +37,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -49,13 +44,13 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; if (!alsoCheckNewChunks && event.isNewChunk()) return; - World world = event.getWorld(); - if (world.getEnvironment() != World.Environment.NETHER) return; - if (exemptedWorlds.contains(world.getName())) return; + if (event.getWorld().getEnvironment() != World.Environment.NETHER) return; + if (exemptedWorlds.contains(event.getWorld().getName())) return; - if (!checkShouldPauseOnLowTPS || AnarchyExploitFixes.getTickReporter().getTPS() >= pauseTPS) { - ChunkUtil.createBedrockLayer(event.getChunk(), world.getMinHeight()); + if (!checkShouldPauseOnLowTPS || AnarchyExploitFixes.tickReporter().getTPS() >= pauseTPS) { + ChunkUtil.createBedrockLayer(event.getChunk(), event.getWorld().getMinHeight()); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherCeiling.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherCeiling.java index 5a4af33aa..a29bb4907 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherCeiling.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherCeiling.java @@ -14,15 +14,16 @@ public class PeriodicallyFillNetherCeiling extends AEFModule implements Consumer { - private ScheduledTask scheduledTask; private final Set exemptedWorlds; private final long checkPeriod; private final double pauseTPS; private final boolean pauseOnLowTPS; - + + private ScheduledTask scheduledTask; + public PeriodicallyFillNetherCeiling() { - super("bedrock.fill-in-bedrock.nether-ceiling.periodically-check-and-fill"); - config.addComment(configPath + ".enable","Only checks loaded chunks."); + super("bedrock.fill-in-bedrock.nether-ceiling.periodically-check-and-fill", false, + "Only checks loaded chunks."); this.checkPeriod = config.getInt(configPath + ".check-period-in-seconds", 10) * 20L; this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", List.of("exampleworld", "exampleworld2"), @@ -34,32 +35,32 @@ public PeriodicallyFillNetherCeiling() { @Override public void enable() { - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @Override public void accept(ScheduledTask task) { - if (pauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getGlobalTPS() <= pauseTPS) return; + if (pauseOnLowTPS && AnarchyExploitFixes.tickReporter().getGlobalTPS() <= pauseTPS) return; for (World world : plugin.getServer().getWorlds()) { if (world.getEnvironment() != World.Environment.NETHER) continue; if (exemptedWorlds.contains(world.getName())) continue; for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!chunk.isEntitiesLoaded()) return; - if (pauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; + if (pauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; ChunkUtil.createBedrockLayer(chunk, config.nether_ceiling_max_y); }); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherFloor.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherFloor.java index f292b3f35..8c3c6ca58 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherFloor.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherFloor.java @@ -14,14 +14,15 @@ public class PeriodicallyFillNetherFloor extends AEFModule implements Consumer { - private ScheduledTask scheduledTask; private final Set exemptedWorlds; private final long checkPeriod; private final double pauseTPS; private final boolean pauseOnLowTPS; + private ScheduledTask scheduledTask; + public PeriodicallyFillNetherFloor() { - super("bedrock.fill-in-bedrock.nether-floor.periodically-check-and-fill"); + super("bedrock.fill-in-bedrock.nether-floor.periodically-check-and-fill", false); config.addComment(configPath + ".enable","Only checks loaded chunks."); this.checkPeriod = config.getInt(configPath + ".check-period-in-seconds", 10) * 20L; this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", @@ -34,32 +35,32 @@ public PeriodicallyFillNetherFloor() { @Override public void enable() { - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @Override public void accept(ScheduledTask task) { - if (pauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getGlobalTPS() <= pauseTPS) return; + if (pauseOnLowTPS && AnarchyExploitFixes.tickReporter().getGlobalTPS() <= pauseTPS) return; for (World world : plugin.getServer().getWorlds()) { if (world.getEnvironment() != World.Environment.NETHER) continue; if (exemptedWorlds.contains(world.getName())) continue; for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!chunk.isEntitiesLoaded()) return; - if (pauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; + if (pauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; ChunkUtil.createBedrockLayer(chunk, world.getMinHeight()); }); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillOverworldFloor.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillOverworldFloor.java index 09e9665a8..df6bd3742 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillOverworldFloor.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillOverworldFloor.java @@ -14,15 +14,16 @@ public class PeriodicallyFillOverworldFloor extends AEFModule implements Consumer { - private ScheduledTask scheduledTask; private final Set exemptedWorlds; private final long checkPeriod; private final double pauseTPS; private final boolean pauseOnLowTPS; + private ScheduledTask scheduledTask; + public PeriodicallyFillOverworldFloor() { - super("bedrock.fill-in-bedrock.overworld-floor.periodically-check-and-fill"); - config.addComment(configPath + ".enable","Only checks loaded chunks."); + super("bedrock.fill-in-bedrock.overworld-floor.periodically-check-and-fill", false, + "Only checks loaded chunks."); this.checkPeriod = config.getInt(configPath + ".check-period-in-seconds", 10) * 20L; this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", List.of("exampleworld", "exampleworld2"), @@ -35,32 +36,32 @@ public PeriodicallyFillOverworldFloor() { @Override public void enable() { - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @Override public void accept(ScheduledTask task) { - if (pauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getGlobalTPS() <= pauseTPS) return; + if (pauseOnLowTPS && AnarchyExploitFixes.tickReporter().getGlobalTPS() <= pauseTPS) return; for (World world : plugin.getServer().getWorlds()) { if (world.getEnvironment() != World.Environment.NORMAL) continue; if (exemptedWorlds.contains(world.getName())) continue; for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!chunk.isEntitiesLoaded()) return; - if (pauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; + if (pauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; ChunkUtil.createBedrockLayer(chunk, world.getMinHeight()); }); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PreventGoingBelowBedrockFloor.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PreventGoingBelowBedrockFloor.java index d406581f8..1fb6bd776 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PreventGoingBelowBedrockFloor.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/bedrock/PreventGoingBelowBedrockFloor.java @@ -23,8 +23,8 @@ public class PreventGoingBelowBedrockFloor extends AEFModule implements Listener private final double damageOnMove; public PreventGoingBelowBedrockFloor() { - super("bedrock.prevent-going-below-bedrock-floor"); - config.addComment(configPath + ".enable", "Prevents players from going below the bedrock floor."); + super("bedrock.prevent-going-below-bedrock-floor", true, + "Prevents players from going below the bedrock floor."); this.vehicleEject = config.getBoolean(configPath + ".leave-vehicle", true, "Whether to make player leave their vehicle."); this.closeElytra = config.getBoolean(configPath + ".stop-elytra", true, @@ -52,11 +52,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chat/PreventPluginScanning.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chat/PreventPluginScanning.java index 3fec1232c..d04ecccc5 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chat/PreventPluginScanning.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chat/PreventPluginScanning.java @@ -1,7 +1,8 @@ package me.xginko.aef.modules.chat; import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.AnarchyExploitFixes; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -16,8 +17,7 @@ public class PreventPluginScanning extends AEFModule implements Listener { public PreventPluginScanning() { - super("chat.prevent-scanning-server-plugins"); - config.addComment(configPath + ".enable",""" + super("chat.prevent-scanning-server-plugins", true,""" Prevents hacked clients running .plugins to find out what plugins\s the server is using.\s Recommended to use in combination with command whitelist."""); @@ -28,11 +28,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -44,7 +39,7 @@ private boolean isSuspectedScanPacket(String buffer) { @EventHandler(priority = EventPriority.HIGHEST) private void onAsyncCommandTabComplete(AsyncTabCompleteEvent event) { - if (event.getSender().hasPermission(AEFPermission.BYPASS_CHAT.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getSender(), AEFPermission.BYPASS_CHAT.node()).toBoolean()) return; if (isSuspectedScanPacket(event.getBuffer())) { event.setCancelled(true); @@ -53,7 +48,7 @@ private void onAsyncCommandTabComplete(AsyncTabCompleteEvent event) { @EventHandler(priority = EventPriority.HIGHEST) private void onCommandTabComplete(TabCompleteEvent event) { - if (event.getSender().hasPermission(AEFPermission.BYPASS_CHAT.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getSender(), AEFPermission.BYPASS_CHAT.node()).toBoolean()) return; if (isSuspectedScanPacket(event.getBuffer())) { event.setCancelled(true); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CommandWhitelist.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CommandWhitelist.java index 4faf7833c..d56496d52 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CommandWhitelist.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CommandWhitelist.java @@ -10,7 +10,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatCommand; import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatMessage; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.CommandUtil; import org.bukkit.entity.Player; @@ -32,17 +32,17 @@ */ public class CommandWhitelist extends AEFModule implements PacketListener, Listener { - private final PacketListenerAbstract abstractListener; - private final Listener commandSendListener; private final Set allowedCommands, bannedSubCommands; private final boolean usePackets, shouldLog; + private PacketListenerAbstract packetListenerAbstract; + private Listener commandSendListener; + public CommandWhitelist() { - super("chat.command-whitelist"); - config.addComment(configPath + ".enable", - "This will make it pretty much impossible to find your plugins as\n" + - "only the commands you specify will be able to work.\n" + - "Allow bypass using permission: " + AEFPermission.BYPASS_CMD_WHITELIST.string()); + super("chat.command-whitelist", false, + "This will make it pretty much impossible to find your plugins as\n" + + "only the commands you specify will be able to work.\n" + + "Allow bypass using permission: " + AEFPermission.BYPASS_CMD_WHITELIST.node()); this.shouldLog = config.getBoolean(configPath + ".log", false, "Will show logs when a command was denied."); this.usePackets = config.getBoolean(configPath + ".use-packets", false,""" @@ -63,33 +63,34 @@ public CommandWhitelist() { List.of("help about", "vote List", "vote Best", "vote Total", "worldstats reload", "stats reload"),""" Add all subcommands you DON'T want your players to be able\s to access. Case sensitive!""")); - this.commandSendListener = new CWCommandSendListener(allowedCommands); - this.abstractListener = asAbstract(PacketListenerPriority.HIGHEST); } @Override public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); + commandSendListener = new CWCommandSendListener(allowedCommands); plugin.getServer().getPluginManager().registerEvents(commandSendListener, plugin); if (usePackets) { - if (config.packets_disabled) { + if (AnarchyExploitFixes.config().packets_disabled) { warn("Can't enable packet listener because packet events is disabled in config."); } else { - PacketEvents.getAPI().getEventManager().registerListener(abstractListener); + packetListenerAbstract = asAbstract(PacketListenerPriority.HIGHEST); + PacketEvents.getAPI().getEventManager().registerListener(packetListenerAbstract); } } } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - HandlerList.unregisterAll(commandSendListener); - PacketEvents.getAPI().getEventManager().unregisterListener(abstractListener); + if (commandSendListener != null) { + HandlerList.unregisterAll(commandSendListener); + commandSendListener = null; + } + if (packetListenerAbstract != null) { + PacketEvents.getAPI().getEventManager().unregisterListener(packetListenerAbstract); + packetListenerAbstract = null; + } } @Override @@ -106,8 +107,8 @@ public void onPacketReceive(PacketReceiveEvent event) { return; } - final Player player = (Player) event.getPlayer(); - if (player != null && player.hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + final Player player = event.getPlayer(); + if (player != null && AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; if (!allowedCommands.contains(CommandUtil.getCommandLabel(message).toLowerCase())) { event.setCancelled(true); @@ -129,7 +130,7 @@ public void onPacketReceive(PacketReceiveEvent event) { @EventHandler(priority = EventPriority.HIGHEST) private void onCommandPreProcess(PlayerCommandPreprocessEvent event) { final Player player = event.getPlayer(); - if (player.hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; String message = event.getMessage(); String commandLabel = CommandUtil.getCommandLabel(message).toLowerCase(); @@ -157,8 +158,7 @@ private void onCommandPreProcess(PlayerCommandPreprocessEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onAsyncCommandTabComplete(AsyncTabCompleteEvent event) { if (event.getCompletions().isEmpty()) return; - if (!(event.getSender() instanceof Player)) return; - if (event.getSender().hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getSender(), AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; event.setCompletions(getFilteredTabCompletions(event.getBuffer(), event.getCompletions())); } @@ -166,8 +166,7 @@ private void onAsyncCommandTabComplete(AsyncTabCompleteEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onCommandTabComplete(TabCompleteEvent event) { if (event.getCompletions().isEmpty()) return; - if (!(event.getSender() instanceof Player)) return; - if (event.getSender().hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getSender(), AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; event.setCompletions(getFilteredTabCompletions(event.getBuffer(), event.getCompletions())); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/BlockLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/BlockLimit.java index 16ffd2913..dc30f7631 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/BlockLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/BlockLimit.java @@ -1,6 +1,8 @@ package me.xginko.aef.modules.chunklimits; import com.cryptomorin.xseries.XMaterial; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import me.xginko.aef.modules.AEFModule; import org.bukkit.Chunk; @@ -10,7 +12,9 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import java.time.Duration; import java.util.EnumMap; import java.util.Map; import java.util.TreeMap; @@ -18,9 +22,14 @@ public class BlockLimit extends AEFModule implements Listener { private final Map blockLimits = new EnumMap<>(Material.class); + private final long materialCountCacheMillis; + + private Cache> chunkMaterialCache; public BlockLimit() { - super("chunk-limits.block-limit"); + super("chunk-limits.block-limit", false); + this.materialCountCacheMillis = config.getLong(configPath + ".material-count-cache-millis", 1000, + "Recommended to not go higher than 5000ms."); Map universal = new EnumMap<>(XMaterial.class); universal.put(XMaterial.ENCHANTING_TABLE, 16); @@ -122,7 +131,7 @@ public BlockLimit() { Map compatible = new TreeMap<>(); for (Map.Entry entry : universal.entrySet()) { if (entry.getKey().isSupported()) { - compatible.put(entry.getKey().parseMaterial().name(), entry.getValue()); + compatible.put(entry.getKey().get().name(), entry.getValue()); } } @@ -143,44 +152,70 @@ public BlockLimit() { @Override public void enable() { + chunkMaterialCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(1)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (chunkMaterialCache != null) { + for (Map.Entry> entry : chunkMaterialCache.asMap().entrySet()) { + entry.getValue().invalidateAll(); + entry.getValue().cleanUp(); + } + chunkMaterialCache.invalidateAll(); + chunkMaterialCache.cleanUp(); + chunkMaterialCache = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPlace(BlockPlaceEvent event) { - final Material placedType = event.getBlock().getType(); - if ( - blockLimits.containsKey(placedType) - && exceedsPerChunkLimit(placedType, blockLimits.get(placedType), event.getBlock().getChunk()) - ) { + if (blockLimits.containsKey(event.getBlock().getType()) + && exceedsPerChunkLimit(event.getBlock().getType(), event.getBlock().getChunk())) { event.setCancelled(true); } } - private boolean exceedsPerChunkLimit(Material material, int limit, Chunk chunk) { + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPlayerInteract(PlayerInteractEvent event) { + if (event.getAction().isLeftClick()) return; + + if (blockLimits.containsKey(event.getMaterial()) + && exceedsPerChunkLimit(event.getMaterial(), event.getPlayer().getChunk())) { + event.setCancelled(true); + } + } + + private boolean exceedsPerChunkLimit(Material blockType, Chunk chunk) { + final int limit = blockLimits.get(blockType); final int minY = chunk.getWorld().getMinHeight(); final int maxY = chunk.getWorld().getMaxHeight(); - int count = 0; - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = minY; y < maxY; y++) { - if (chunk.getBlock(x, y, z).getType() == material) { - count++; - if (count > limit) return true; + + Cache exceededCache = chunkMaterialCache.getIfPresent(chunk); + if (exceededCache == null) { + exceededCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(materialCountCacheMillis)).build(); + } + + Boolean exceeded = exceededCache.get(blockType, material -> { + int count = 0; + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = minY; y < maxY; y++) { + if (chunk.getBlock(x, y, z).getType() == material) { + count++; + if (count > limit) { + return true; + } + } } } } - } - return false; + return false; + }); + + chunkMaterialCache.put(chunk, exceededCache); + return exceeded; } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/CustomEntityLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/CustomEntityLimit.java index a1778ca5c..afa44b402 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/CustomEntityLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/CustomEntityLimit.java @@ -4,6 +4,7 @@ import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; import org.bukkit.Material; @@ -25,15 +26,16 @@ public class CustomEntityLimit extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; private final Map entityLimits = new EnumMap<>(EntityType.class); private final long checkPeriod, minChunkAge; private final boolean logIsEnabled, enableChunkAgeSkip, forceLoadEntities; + private ScheduledTask scheduledTask; + public CustomEntityLimit() { - super("chunk-limits.entity-limits.custom-limit"); - config.addComment(configPath + ".enable", """ - Limit specific entity types per chunk."""); + super("chunk-limits.entity-limits.custom-limit", false, """ + Limit specific entity types per chunk.\s + Read over the defaults at least once before enabling."""); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", true); this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 1200, """ Check all loaded chunks every x ticks."""); @@ -153,11 +155,6 @@ public void enable() { .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -166,6 +163,8 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChunkUnload(ChunkUnloadEvent event) { + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; + for (Map.Entry limit : entityLimits.entrySet()) { final int maxAllowedPerChunk = limit.getValue(); @@ -186,14 +185,13 @@ private void onChunkUnload(ChunkUnloadEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onSpawn(EntitySpawnEvent event) { - final EntityType spawnedType = event.getEntityType(); - if (!entityLimits.containsKey(spawnedType)) return; + if (!entityLimits.containsKey(event.getEntityType())) return; - final int maxAllowedPerChunk = entityLimits.get(spawnedType); + final int maxAllowedPerChunk = entityLimits.get(event.getEntityType()); int entityCount = 0; for (Entity entity : event.getEntity().getChunk().getEntities()) { - if (entity.getType() != spawnedType) continue; + if (entity.getType() != event.getEntityType()) continue; entityCount++; if (entityCount <= maxAllowedPerChunk) continue; @@ -208,6 +206,8 @@ private void onSpawn(EntitySpawnEvent event) { public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!forceLoadEntities && !chunk.isEntitiesLoaded()) return; if (enableChunkAgeSkip && chunk.getInhabitedTime() < minChunkAge) return; @@ -215,16 +215,15 @@ public void accept(ScheduledTask task) { Entity[] chunkEntities = chunk.getEntities(); for (Map.Entry limit : entityLimits.entrySet()) { - final int maxAllowedPerChunk = limit.getValue(); AtomicInteger count = new AtomicInteger(); for (Entity entity : chunkEntities) { entity.getScheduler().execute(plugin, () -> { if (entity.getType() != limit.getKey()) return; - if (count.incrementAndGet() <= maxAllowedPerChunk) return; + if (count.incrementAndGet() <= limit.getValue()) return; entity.remove(); if (logIsEnabled) info("Removed entity " + entity.getType() + " at " + - LocationUtil.toString(entity.getLocation()) + " because reached limit of " + maxAllowedPerChunk); + LocationUtil.toString(entity.getLocation()) + " because reached limit of " + limit.getValue()); }, null, 1L); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java index aa35d74f3..e4a650835 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java @@ -6,6 +6,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.models.ChunkUID; import org.bukkit.Chunk; @@ -18,10 +19,11 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.entity.ItemSpawnEvent; -import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.EntitiesLoadEvent; import java.time.Duration; import java.util.EnumSet; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -30,16 +32,16 @@ public class DroppedItemLimit extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; - private final Cache scheduledChecks; private final Set whitelistedTypes; private final long checkPeriod, cleanupDelay; private final int maxDroppedItemsPerChunk; - private final boolean logIsEnabled, usingWhitelist, onChunkLoad; + private final boolean logIsEnabled, usingWhitelist, onEntitiesLoad; + + private Cache scheduledChecks; + private ScheduledTask scheduledTask; public DroppedItemLimit() { - super("chunk-limits.entity-limits.dropped-item-limit"); - config.addComment(configPath + ".enable", """ + super("chunk-limits.entity-limits.dropped-item-limit", false, """ Limit the amount of dropped items in a chunk to combat lag.\s Be aware this does not prioritize items by value or anything,\s it just deletes whatever happens to get over the limit during\s @@ -55,9 +57,8 @@ public DroppedItemLimit() { The period in ticks in which all loaded chunks should be regularly\s checked. Keep in mind: A lower number provides more accuracy but is\s also worse for performance."""); - this.scheduledChecks = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cleanupDelay * 50L)).build(); - this.onChunkLoad = config.getBoolean(configPath + ".check-on-chunk-load", true, """ - Runs item check when a chunk is loaded."""); + this.onEntitiesLoad = config.getBoolean(configPath + ".check-on-entities-load", true, """ + Runs item check when a chunk's entities are loaded."""); this.usingWhitelist = config.getBoolean(configPath + ".whitelist-specific-item-types", false); this.whitelistedTypes = config.getList(configPath + ".whitelisted-types", MaterialTags.SHULKER_BOXES.getValues().stream().map(Enum::name).sorted().toList(), """ @@ -79,21 +80,27 @@ public DroppedItemLimit() { @Override public void enable() { + scheduledChecks = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cleanupDelay * 50L)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (scheduledTask != null) scheduledTask.cancel(); - scheduledChecks.asMap().forEach((chunk, queuedCheck) -> queuedCheck.cancel()); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } + if (scheduledChecks != null) { + for (Map.Entry entry : scheduledChecks.asMap().entrySet()) { + entry.getValue().cancel(); + } + scheduledChecks.invalidateAll(); + scheduledChecks.cleanUp(); + scheduledChecks = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -123,12 +130,12 @@ private void onItemDrop(ItemSpawnEvent event) { } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onChunkLoad(ChunkLoadEvent event) { - if (!onChunkLoad || event.isNewChunk()) return; + private void onEntitiesLoad(EntitiesLoadEvent event) { + if (!onEntitiesLoad) return; int droppedItemCount = 0; - for (Entity entity : event.getChunk().getEntities()) { + for (Entity entity : event.getEntities()) { if (entity.getType() != XEntityType.ITEM.get()) continue; droppedItemCount++; @@ -145,6 +152,8 @@ private void onChunkLoad(ChunkLoadEvent event) { public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!chunk.isEntitiesLoaded()) return; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/ExpBottleLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/ExpBottleLimit.java deleted file mode 100755 index decc98554..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/ExpBottleLimit.java +++ /dev/null @@ -1,99 +0,0 @@ -package me.xginko.aef.modules.chunklimits; - -import com.cryptomorin.xseries.XEntityType; -import io.papermc.paper.threadedregions.scheduler.ScheduledTask; -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.LocationUtil; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.ExpBottleEvent; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -public class ExpBottleLimit extends AEFModule implements Consumer, Listener { - - private ScheduledTask scheduledTask; - private final long checkPeriod; - private final int maxExpBottlePerChunk; - private final boolean logIsEnabled; - - public ExpBottleLimit() { - super("chunk-limits.exp-bottle-limit"); - config.addComment(configPath + ".enable", """ - Prevent players from crashing the server or other players by\s - creating a ton of THROWN_EXP_BOTTLE entities, then loading\s - them at once.\s - Does not limit the EXP_ORBS, just the bottle entities."""); - this.logIsEnabled = config.getBoolean(configPath + ".log", false); - this.maxExpBottlePerChunk = config.getInt(configPath + ".max-exp-bottle-per-chunk", 25); - this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 800, - "20 ticks = 1 second"); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() - .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - if (scheduledTask != null) scheduledTask.cancel(); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onExpBottle(ExpBottleEvent event) { - int expBottleCount = 0; - - for (Entity entity : event.getEntity().getChunk().getEntities()) { - if (entity.getType() != XEntityType.EXPERIENCE_BOTTLE.get()) continue; - - expBottleCount++; - - if (expBottleCount > maxExpBottlePerChunk) { - entity.getScheduler().execute(plugin, () -> { - entity.remove(); - if (logIsEnabled) info("Removed XP-Bottle at " + LocationUtil.toString(entity.getLocation()) + - " because reached limit of " + maxExpBottlePerChunk); - }, null, 1L); - } - } - } - - @Override - public void accept(ScheduledTask task) { - for (World world : plugin.getServer().getWorlds()) { - for (Chunk chunk : world.getLoadedChunks()) { - plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { - if (!chunk.isEntitiesLoaded()) return; - - AtomicInteger droppedItemCount = new AtomicInteger(); - - for (Entity entity : chunk.getEntities()) { - entity.getScheduler().execute(plugin, () -> { - if (entity.getType() != XEntityType.EXPERIENCE_BOTTLE.get()) return; - if (droppedItemCount.incrementAndGet() <= maxExpBottlePerChunk) return; - - entity.remove(); - if (logIsEnabled) info("Removed XP-Bottle at " + LocationUtil.toString(entity.getLocation()) + - " because reached limit of " + maxExpBottlePerChunk); - }, null, 1L); - } - }); - } - } - } -} \ No newline at end of file diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/FallingBlockLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/FallingBlockLimit.java index f39f9072a..58f8f26a1 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/FallingBlockLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/FallingBlockLimit.java @@ -2,6 +2,7 @@ import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.models.ChunkUID; import me.xginko.aef.utils.models.ExpiringSet; @@ -18,44 +19,47 @@ public class FallingBlockLimit extends AEFModule implements Listener { - private final ExpiringSet checkedChunks; + private final long chunkCheckDelay; private final int maxFallingGravityBlockPerChunk; private final boolean logIsEnabled; + private ExpiringSet checkedChunks; + public FallingBlockLimit() { - super("chunk-limits.falling-block-limit"); - config.addComment(configPath + ".enable", """ + super("chunk-limits.falling-block-limit", true, """ Prevent players from placing massive sand chunks, then collapsing\s them to kill the server."""); this.logIsEnabled = config.getBoolean(configPath + ".log", false); this.maxFallingGravityBlockPerChunk = config.getInt(configPath + ".max-falling-gravity-blocks-per-chunk", 60, """ Removes any falling block if there is more than x blocks actively\s falling in a chunk."""); - long chunkCheckDelay = Math.max(1, config.getInt(configPath + ".chunk-check-delay-in-ticks", 20, """ + this.chunkCheckDelay = Math.max(1, config.getInt(configPath + ".chunk-check-delay-in-ticks", 20, """ Delay in ticks until the same chunk can be checked again.\s Prevents overchecking, because physics events can be called many\s times in a short time for the same chunk.""")) * 50L; - this.checkedChunks = new ExpiringSet<>(Duration.ofMillis(chunkCheckDelay)); } @Override public void enable() { + checkedChunks = new ExpiringSet<>(Duration.ofMillis(chunkCheckDelay)); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (checkedChunks != null) { + checkedChunks.clear(); + checkedChunks.cleanUp(); + checkedChunks = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPhysics(BlockPhysicsEvent event) { Chunk chunk = event.getBlock().getChunk(); + if (ChunkUtil.isRetrievalUnsafe(chunk)) return; + final ChunkUID chunkUID = ChunkUID.of(chunk); if (checkedChunks.contains(chunkUID)) return; @@ -81,8 +85,10 @@ private void onBlockPhysics(BlockPhysicsEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChangeBlock(EntityChangeBlockEvent event) { - if (!event.getEntityType().equals(XEntityType.FALLING_BLOCK.get())) return; + if (event.getEntityType() != XEntityType.FALLING_BLOCK.get()) return; Chunk chunk = event.getBlock().getChunk(); + if (ChunkUtil.isRetrievalUnsafe(chunk)) return; + final ChunkUID chunkUID = ChunkUID.of(chunk); if (checkedChunks.contains(chunkUID)) return; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/MinecartLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/MinecartLimit.java index f6b4c9e18..8e51ba145 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/MinecartLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/MinecartLimit.java @@ -2,6 +2,7 @@ import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; @@ -19,14 +20,14 @@ public class MinecartLimit extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; private final long checkPeriod; private final int maxMinecartsPerChunk; private final boolean logIsEnabled; + private ScheduledTask scheduledTask; + public MinecartLimit() { - super("chunk-limits.minecart-limit"); - config.addComment(configPath + ".enable", """ + super("chunk-limits.minecart-limit", false, """ Limit the amount of minecarts to prevent lag caused by collisions."""); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", false); this.maxMinecartsPerChunk = config.getInt(configPath + ".max-minecarts-per-chunk", 25); @@ -36,19 +37,17 @@ public MinecartLimit() { @Override public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); HandlerList.unregisterAll(this); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -76,6 +75,8 @@ private void onCreate(VehicleCreateEvent event) { public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!chunk.isEntitiesLoaded()) return; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/NonLivingEntityLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/NonLivingEntityLimit.java index ce299f35b..1f04fb8ce 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/NonLivingEntityLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/NonLivingEntityLimit.java @@ -1,7 +1,9 @@ package me.xginko.aef.modules.chunklimits; +import com.cryptomorin.xseries.XEntityType; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; @@ -19,19 +21,20 @@ public class NonLivingEntityLimit extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; private final long checkPeriod; private final int maxNonLivingEntities; private final boolean logIsEnabled; + private ScheduledTask scheduledTask; + public NonLivingEntityLimit() { - super("chunk-limits.entity-limits.non-living-limit"); - config.addComment(configPath + ".enable", """ + super("chunk-limits.entity-limits.non-living-limit", false, """ Limit the amount of non living entities in a chunk to prevent lag.\s Ignores dropped items."""); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", true); this.maxNonLivingEntities = config.getInt(configPath + ".max-non-living-per-chunk", 100); - this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 20); + this.checkPeriod = Math.max(1, config.getInt(configPath + ".check-period-in-ticks", 20, + "20 ticks = 1 second")); } @Override @@ -41,25 +44,23 @@ public void enable() { .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); HandlerList.unregisterAll(this); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onSpawn(EntitySpawnEvent event) { - if (event.getEntityType().equals(EntityType.DROPPED_ITEM) || EntityUtil.isLivingEntity(event.getEntity())) return; + if (event.getEntityType() != XEntityType.ITEM.get() || EntityUtil.isLivingEntity(event.getEntity())) return; int nonLivingCount = 0; for (Entity entity : event.getEntity().getChunk().getEntities()) { - if (entity.getType().equals(EntityType.DROPPED_ITEM)) continue; + if (entity.getType() != XEntityType.ITEM.get()) continue; if (EntityUtil.isLivingEntity(entity)) continue; nonLivingCount++; @@ -81,6 +82,8 @@ private void onSpawn(EntitySpawnEvent event) { public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!chunk.isEntitiesLoaded()) return; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/ProjectileLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/ProjectileLimit.java new file mode 100755 index 000000000..8d189043a --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/ProjectileLimit.java @@ -0,0 +1,141 @@ +package me.xginko.aef.modules.chunklimits; + +import com.cryptomorin.xseries.XEntityType; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; +import me.xginko.aef.utils.EntityUtil; +import me.xginko.aef.utils.LocationUtil; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; + +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ProjectileLimit extends AEFModule implements Consumer, Listener { + + private final Set exemptEntities; + private final long checkPeriod; + private final int maxProjectilesPerChunk; + private final boolean logIsEnabled; + + private ScheduledTask scheduledTask; + + public ProjectileLimit() { + super("chunk-limits.projectile-limit", true, """ + Prevent players from crashing the server or other players by\s + creating a ton of projectile entities, then loading them at once."""); + this.logIsEnabled = config.getBoolean(configPath + ".log", false); + this.maxProjectilesPerChunk = config.getInt(configPath + ".max-projectiles-per-chunk", 25); + this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 800, + "20 ticks = 1 second"); + final List defaults = Stream.of( + XEntityType.ENDER_PEARL, + XEntityType.FISHING_BOBBER) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList()); + this.exemptEntities = config.getList(configPath + ".whitelisted-types", defaults) + .stream() + .map(configuredEntity -> { + try { + return EntityType.valueOf(configuredEntity); + } catch (IllegalArgumentException e) { + notRecognized(EntityType.class, configuredEntity); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityType.class))); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onProjectileLaunch(ProjectileLaunchEvent event) { + int projectilesCount = 0; + + for (Entity entity : event.getEntity().getChunk().getEntities()) { + if (exemptEntities.contains(entity.getType()) || !EntityUtil.isProjectile(entity)) continue; + + projectilesCount++; + + if (projectilesCount > maxProjectilesPerChunk) { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onProjectileHit(ProjectileHitEvent event) { + int projectilesCount = 0; + + for (Entity entity : event.getEntity().getChunk().getEntities()) { + if (exemptEntities.contains(entity.getType()) || !EntityUtil.isProjectile(entity)) continue; + + projectilesCount++; + + if (projectilesCount > maxProjectilesPerChunk) { + entity.remove(); + if (logIsEnabled) info("Removed Projectile at " + LocationUtil.toString(entity.getLocation()) + + " because reached limit of " + maxProjectilesPerChunk); + } + } + } + + @Override + public void accept(ScheduledTask task) { + for (World world : plugin.getServer().getWorlds()) { + for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { + if (!chunk.isEntitiesLoaded()) return; + + AtomicInteger projectileCount = new AtomicInteger(); + + for (Entity entity : chunk.getEntities()) { + entity.getScheduler().execute(plugin, () -> { + if (exemptEntities.contains(entity.getType()) || !EntityUtil.isProjectile(entity)) return; + if (projectileCount.incrementAndGet() <= maxProjectilesPerChunk) return; + + entity.remove(); + if (logIsEnabled) info("Removed Projectile at " + LocationUtil.toString(entity.getLocation()) + + " because reached limit of " + maxProjectilesPerChunk); + }, null, 1L); + } + }); + } + } + } +} \ No newline at end of file diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/TileEntityLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/TileEntityLimit.java index b87525f97..34d142a2f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/TileEntityLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/TileEntityLimit.java @@ -1,10 +1,11 @@ package me.xginko.aef.modules.chunklimits; +import com.cryptomorin.xseries.XMaterial; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.event.HandlerList; @@ -14,13 +15,14 @@ public class TileEntityLimit extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; private final long checkPeriod; private final int maxTileEntities; private final boolean logIsEnabled; + private ScheduledTask scheduledTask; + public TileEntityLimit() { - super("chunk-limits.entity-limits.tile-entity-limit"); + super("chunk-limits.entity-limits.tile-entity-limit", false); config.addComment(configPath + ".enable", """ Limit the amount of tile entities in a chunk to prevent lag."""); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", true); @@ -35,31 +37,33 @@ public void enable() { .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); HandlerList.unregisterAll(this); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @Override public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { BlockState[] tileEntities = chunk.getTileEntities(false); int tooMany = tileEntities.length - maxTileEntities; if (tooMany <= 0) return; for (int i = 0; i < tooMany; i++) { - tileEntities[i].setType(Material.AIR); + tileEntities[i].setType(XMaterial.AIR.get()); + tileEntities[i].update(true, false); + if (logIsEnabled) - info( "Removed tile entity at "+LocationUtil.toString(tileEntities[i].getLocation())+ - " because reached limit of "+maxTileEntities); + info("Removed tile entity at " + LocationUtil.toString(tileEntities[i].getLocation()) + + " because reached limit of " + maxTileEntities); } }); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VehicleLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VehicleLimit.java index 810a2af3a..2e08c70ca 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VehicleLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VehicleLimit.java @@ -2,6 +2,7 @@ import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; @@ -18,21 +19,21 @@ public class VehicleLimit extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; private final long checkPeriod; private final int maxVehiclesPerChunk; private final boolean logIsEnabled; + private ScheduledTask scheduledTask; + public VehicleLimit() { - super("chunk-limits.vehicle-limit"); - config.addComment(configPath + ".enable", """ + super("chunk-limits.vehicle-limit", false, """ Limit the amount of vehicles to prevent some lag machines.\s ex. dispenser that spawns a lot of boats into a single location\s then hitting it, causing all boats to explode in every direction."""); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", false); this.maxVehiclesPerChunk = config.getInt(configPath + ".max-vehicles-per-chunk", 25); - this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 400, - "200 ticks = 10 seconds."); + this.checkPeriod = Math.max(1, config.getInt(configPath + ".check-period-in-ticks", 400, + "200 ticks = 10 seconds.")); } @Override @@ -42,15 +43,13 @@ public void enable() { .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); HandlerList.unregisterAll(this); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -76,6 +75,8 @@ private void onCreate(VehicleCreateEvent event) { public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!chunk.isEntitiesLoaded()) return; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java index 3b6bbf1de..bfb7be4ec 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java @@ -3,6 +3,7 @@ import com.cryptomorin.xseries.XEntityType; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; import org.bukkit.World; @@ -26,19 +27,20 @@ public class VillagerLimit extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; private final List removalPriority; private final Set professionWhitelist; private final long checkPeriod; private final int maxVillagersPerChunk; private final boolean logIsEnabled, whitelistEnabled; + private ScheduledTask scheduledTask; + public VillagerLimit() { - super("chunk-limits.entity-limits.villager-limit"); + super("chunk-limits.entity-limits.villager-limit", false); this.maxVillagersPerChunk = Math.max(1, config.getInt(configPath + ".max-villagers-per-chunk", 25)); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", false); - this.checkPeriod = Math.max(config.getInt(configPath + ".check-period-in-ticks", 600, - "Check all chunks every x ticks."), 1); + this.checkPeriod = Math.max(1, config.getInt(configPath + ".check-period-in-ticks", 600, + "Check all chunks every x ticks.")); final List defPriority = Stream.of("NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER", "FLETCHER", "MASON", "FARMER", "ARMORER", "TOOLSMITH", "WEAPONSMITH", "CLERIC", "LIBRARIAN") .filter(prof -> { @@ -93,24 +95,22 @@ public VillagerLimit() { @Override public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (scheduledTask != null) scheduledTask.cancel(); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onCreatureSpawn(CreatureSpawnEvent event) { - if (event.getEntityType().equals(XEntityType.VILLAGER.get())) { + if (event.getEntityType() == XEntityType.VILLAGER.get()) { this.checkVillagersInChunk(event.getEntity().getChunk()); } } @@ -119,6 +119,8 @@ private void onCreatureSpawn(CreatureSpawnEvent event) { public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (chunk.isEntitiesLoaded()) { this.checkVillagersInChunk(chunk); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/BowBomb.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/BowBomb.java index eb6c83ef5..e7531a8ba 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/BowBomb.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/BowBomb.java @@ -13,7 +13,7 @@ public class BowBomb extends AEFModule implements Listener { private final int maxBowSquaredVelocity; public BowBomb() { - super("combat.prevent-bow-bomb"); + super("combat.prevent-bow-bomb", false); this.maxBowSquaredVelocity = config.getInt(configPath + ".max-bow-squared-velocity", 15, "Fully pulled bow is ~9-10. 15 is default just to be safe."); } @@ -23,11 +23,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/Burrow.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/Burrow.java index cf43023b3..dc6971a9e 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/Burrow.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/Burrow.java @@ -31,7 +31,7 @@ public class Burrow extends AEFModule implements Listener { private final boolean shouldTeleportUp, preventIfBlockAboveBurrow, breakAnvilInsteadOfTP, allowSlabs; public Burrow() { - super("combat.prevent-burrow"); + super("combat.prevent-burrow", false); this.damageWhenMovingInBurrow = config.getDouble(configPath + ".damage-when-moving",1.0, """ 1.0 = Half a heart of damage every time you move."""); this.shouldTeleportUp = config.getBoolean(configPath + ".teleport-above-block", true); @@ -47,7 +47,7 @@ public Burrow() { List defaults = Stream.concat(XTag.SHULKER_BOXES.getValues().stream(), Stream.of(XMaterial.AIR, XMaterial.DIRT, XMaterial.DIRT_PATH, XMaterial.SAND, XMaterial.GRAVEL)) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .map(Enum::name) .toList(); this.ignoredMaterial = config.getList(configPath + ".ignored-materials", defaults) @@ -69,11 +69,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -102,12 +97,12 @@ private void onPlayerMove(PlayerMoveEvent event) { final Block burrowBlock = playerLocation.getBlock(); if (ignoredMaterial.contains(burrowBlock.getType())) return; - if (!preventIfBlockAboveBurrow && burrowBlock.getRelative(BlockFace.UP).getType() != XMaterial.AIR.parseMaterial()) { + if (!preventIfBlockAboveBurrow && !burrowBlock.getRelative(BlockFace.UP).getType().isAir()) { return; } // Beacon and Indestructibles - if (MaterialUtil.SOLID_INDESTRUCTIBLES.contains(burrowBlock.getType()) || burrowBlock.getType() == XMaterial.BEACON.parseMaterial()) { + if (MaterialUtil.SOLID_INDESTRUCTIBLES.contains(burrowBlock.getType()) || burrowBlock.getType() == XMaterial.BEACON.get()) { player.damage(damageWhenMovingInBurrow); if (shouldTeleportUp) teleportUpAndCenter(player, burrowBlock.getLocation()); return; @@ -126,7 +121,7 @@ private void onPlayerMove(PlayerMoveEvent event) { if (MaterialUtil.ANVILS.contains(burrowBlock.getType())) { player.damage(damageWhenMovingInBurrow); if (breakAnvilInsteadOfTP) { - burrowBlock.setType(XMaterial.AIR.parseMaterial()); + burrowBlock.setType(XMaterial.AIR.get()); } else { if (shouldTeleportUp) teleportUpAndCenter(player, burrowBlock.getLocation()); } @@ -134,7 +129,7 @@ private void onPlayerMove(PlayerMoveEvent event) { } // Ender chest & Blocks that are slightly lower in height - if (burrowBlock.getType() == XMaterial.ENDER_CHEST.parseMaterial() || MaterialUtil.SINK_IN_BLOCKS.contains(burrowBlock.getType())) { + if (burrowBlock.getType() == XMaterial.ENDER_CHEST.get() || MaterialUtil.SINK_IN_BLOCKS.contains(burrowBlock.getType())) { if (playerLocation.getY() - playerLocation.getBlockY() < 0.875) { player.damage(damageWhenMovingInBurrow); if (shouldTeleportUp) teleportUpAndCenter(player, burrowBlock.getLocation()); @@ -143,7 +138,7 @@ private void onPlayerMove(PlayerMoveEvent event) { } // Enchantment Table - if (burrowBlock.getType() == XMaterial.ENCHANTING_TABLE.parseMaterial()) { + if (burrowBlock.getType() == XMaterial.ENCHANTING_TABLE.get()) { if (playerLocation.getY() - playerLocation.getBlockY() < 0.75) { player.damage(damageWhenMovingInBurrow); if (shouldTeleportUp) teleportUpAndCenter(player, burrowBlock.getLocation()); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/MultiTask.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/MultiTask.java index c3ee3098b..2813dcd6e 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/MultiTask.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/MultiTask.java @@ -15,7 +15,7 @@ public class MultiTask extends AEFModule implements Listener { public MultiTask() { - super("combat.multi-task-patch"); + super("combat.multi-task-patch", false); } @Override @@ -23,11 +23,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PistonCrystalDelay.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PistonCrystalDelay.java index 5484c096d..380165ea0 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PistonCrystalDelay.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PistonCrystalDelay.java @@ -2,7 +2,6 @@ import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.models.ExpiringSet; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; @@ -11,42 +10,47 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPistonExtendEvent; -import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; public class PistonCrystalDelay extends AEFModule implements Listener { - private final ExpiringSet pistonsPushingCrystals; + private final long cooldownNanos; + + private Map extendCooldowns; public PistonCrystalDelay() { - super("combat.crystal-aura.piston-aura-delay"); - config.addComment(configPath+".enable", "Rate-limits pistons that extend into crystals."); - this.pistonsPushingCrystals = new ExpiringSet<>(Duration.ofMillis( - Math.max(1, config.getInt(configPath + ".piston-extend-delay-in-ticks", 40)) * 50L)); + super("combat.crystal-aura.piston-aura-delay", false, + "Rate-limits pistons that extend into crystals."); + this.cooldownNanos = TimeUnit.MILLISECONDS.toNanos( + Math.max(1, config.getInt(configPath + ".piston-extend-delay-in-ticks", 40)) * 50L); } @Override public void enable() { + extendCooldowns = new ConcurrentHashMap<>(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath+".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (extendCooldowns != null) { + extendCooldowns.clear(); + extendCooldowns = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPistonExtend(BlockPistonExtendEvent event) { for (Entity entity : event.getBlock().getRelative(event.getDirection()).getLocation().getNearbyEntities(1, 1, 1)) { if (entity.getType() == XEntityType.END_CRYSTAL.get()) { - if (pistonsPushingCrystals.contains(event.getBlock().getLocation())) { + if (extendCooldowns.containsKey(event.getBlock().getLocation()) + && extendCooldowns.get(event.getBlock().getLocation()) > System.nanoTime()) { event.setCancelled(true); } else { - pistonsPushingCrystals.add(event.getBlock().getLocation()); + extendCooldowns.put(event.getBlock().getLocation(), System.currentTimeMillis() + cooldownNanos); } return; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PistonPush.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PistonPush.java index b03c60595..0db54a92f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PistonPush.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PistonPush.java @@ -20,11 +20,10 @@ public class PistonPush extends AEFModule implements Listener { private final Set pushDisabledTypes; public PistonPush() { - super("combat.piston-push"); - config.addComment(configPath+".enable", - "Disables pistons from extending if it would push certain configured entities.\n" + - "This can be used to prevent players from pushing other players out of burrows, by\n" + - "configuring PLAYER, or to disable piston-crystal by adding ENDER_CRYSTAL to the list."); + super("combat.piston-push", false,""" + Disables pistons from extending if it would push certain configured entities. + This can be used to prevent players from pushing other players out of burrows, by + configuring PLAYER, or to disable piston-crystal by adding ENDER_CRYSTAL to the list."""); this.pushDisabledTypes = config.getList(configPath+".piston-push-blocked-entities", Collections.singletonList("PLAYER")) .stream() .map(configuredType -> { @@ -43,11 +42,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath+".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PortalGodMode.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PortalGodMode.java index 4863b307f..dc351ae89 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PortalGodMode.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/PortalGodMode.java @@ -20,12 +20,12 @@ public class PortalGodMode extends AEFModule implements Listener { - private final Cache playersWaitingForPortalTeleport; private final long delayTicks; + private Cache playersWaitingForPortalTeleport; + public PortalGodMode() { - super("combat.portal-god-mode-patch"); - config.addComment(configPath + ".enable", """ + super("combat.portal-god-mode-patch", false, """ Prevents an exploit that allows players to stand in nether portals and not\s take damage indefinitely by just never sending a TeleportConfirm packet to\s the server.\s @@ -36,23 +36,23 @@ public PortalGodMode() { the portal will be broken, making the player inside vulnerable again.\s Nether portal teleports normally happen within ~3s after enter, so 5s (100ticks)\s should be a safe value."""); - this.playersWaitingForPortalTeleport = Caffeine.newBuilder() - .expireAfterWrite(Duration.ofMillis((delayTicks * 50L) + 1000L)).build(); // Keep cached content for a second longer just in case } @Override public void enable() { + playersWaitingForPortalTeleport = Caffeine.newBuilder() + .expireAfterWrite(Duration.ofMillis((delayTicks * 50L) + 1000L)).build(); // Keep cached content for a second longer just in case plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (playersWaitingForPortalTeleport != null) { + playersWaitingForPortalTeleport.invalidateAll(); + playersWaitingForPortalTeleport.cleanUp(); + playersWaitingForPortalTeleport = null; + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -63,7 +63,7 @@ private void onEntityPortalEnter(EntityPortalEnterEvent event) { playersWaitingForPortalTeleport.put(event.getEntity().getUniqueId(), plugin.getServer().getRegionScheduler().runDelayed(plugin, event.getLocation(), breakPortal -> { - event.getLocation().getBlock().setType(XMaterial.AIR.parseMaterial(), true); + event.getLocation().getBlock().setType(XMaterial.AIR.get(), true); playersWaitingForPortalTeleport.invalidate(event.getEntity().getUniqueId()); }, delayTicks)); } @@ -85,7 +85,7 @@ private void onPlayerMove(PlayerMoveEvent event) { @Nullable ScheduledTask breakPortalTask = playersWaitingForPortalTeleport.getIfPresent(event.getPlayer().getUniqueId()); if (breakPortalTask == null) return; - if (event.getTo().getBlock().getType() != XMaterial.NETHER_PORTAL.parseMaterial()) { + if (event.getTo().getBlock().getType() != XMaterial.NETHER_PORTAL.get()) { breakPortalTask.cancel(); playersWaitingForPortalTeleport.invalidate(event.getPlayer().getUniqueId()); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/SilentSwapDelay.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/SilentSwapDelay.java index fe33809c9..64d80945b 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/SilentSwapDelay.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/SilentSwapDelay.java @@ -2,12 +2,14 @@ import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.inventory.InventoryInteractEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.player.PlayerKickEvent; @@ -20,32 +22,34 @@ public class SilentSwapDelay extends AEFModule implements Listener { - private final Map swapItemCooldowns; private final long cooldownNanos; + private final boolean updateInventory; + + private Map swapItemCooldowns; public SilentSwapDelay() { - super("combat.silent-swap-delay"); - this.swapItemCooldowns = new ConcurrentHashMap<>(); - this.cooldownNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(configPath + ".min-swap-delay-millis", 40L,""" - The delay in millis a player cant swap hotbar items after placing - a block, clicking a block (for example to place a crystal) or - damaging an entity. (50 ms = 1 tick)""")); + super("combat.silent-swap-delay", false); + this.updateInventory = config.getBoolean(configPath + ".update-inventory-on-cancel", false, + "Can help with desync but recommended to leave off unless you have issues."); + this.cooldownNanos = TimeUnit.MILLISECONDS.toNanos(config.getLong(configPath + ".min-swap-delay-millis", 40L,""" + The delay in millis a player cant swap hotbar items after placing + a block, clicking a block (for example to place a crystal) or + damaging an entity. (50 ms = 1 tick)""")); } @Override public void enable() { + swapItemCooldowns = new ConcurrentHashMap<>(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (swapItemCooldowns != null) { + swapItemCooldowns.clear(); + swapItemCooldowns = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -54,6 +58,17 @@ private void onPlayerItemHeld(PlayerItemHeldEvent event) { // Fired when a hot b if (swapItemCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime()) { event.setCancelled(true); + if (updateInventory) event.getPlayer().updateInventory(); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onInventoryInteract(InventoryInteractEvent event) { + if (!swapItemCooldowns.containsKey(event.getWhoClicked().getUniqueId())) return; + + if (swapItemCooldowns.get(event.getWhoClicked().getUniqueId()) > System.nanoTime()) { + event.setCancelled(true); + if (updateInventory) ((Player) event.getWhoClicked()).updateInventory(); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java index 10222c847..a0ddfad4e 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java @@ -18,8 +18,8 @@ public AnchorAuraDelay() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerInteract(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; - if (event.getClickedBlock().getType() != XMaterial.RESPAWN_ANCHOR.parseMaterial()) return; - if (event.getItem() == null || event.getItem().getType() != XMaterial.GLOWSTONE.parseMaterial()) return; + if (event.getClickedBlock().getType() != XMaterial.RESPAWN_ANCHOR.get()) return; + if (event.getItem() == null || event.getItem().getType() != XMaterial.GLOWSTONE.get()) return; if (event.getPlayer().getWorld().isRespawnAnchorWorks()) return; for (Map.Entry entry : cooldownSettings.entrySet()) { @@ -35,7 +35,7 @@ private void onPlayerInteract(PlayerInteractEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPlace(BlockPlaceEvent event) { - if (event.getBlock().getType() != XMaterial.RESPAWN_ANCHOR.parseMaterial()) return; + if (event.getBlock().getType() != XMaterial.RESPAWN_ANCHOR.get()) return; if (event.getPlayer().getWorld().isRespawnAnchorWorks()) return; for (Map.Entry entry : cooldownSettings.entrySet()) { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java index 47543cc3e..a35afc960 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java @@ -19,7 +19,7 @@ public abstract class AuraDelayModule extends AEFModule implements Listener { protected static class Cooldowns { - public final Map placeCooldowns, breakCooldowns; + public Map placeCooldowns, breakCooldowns; public final long placeDelayNanos, breakDelayNanos; public Cooldowns(long placeDelayMillis, long breakDelayMillis) { @@ -28,13 +28,23 @@ public Cooldowns(long placeDelayMillis, long breakDelayMillis) { this.placeDelayNanos = TimeUnit.MILLISECONDS.toNanos(placeDelayMillis); this.breakDelayNanos = TimeUnit.MILLISECONDS.toNanos(breakDelayMillis); } + + public void clear() { + placeCooldowns.clear(); + breakCooldowns.clear(); + placeCooldowns = breakCooldowns = null; + } } protected final Map cooldownSettings = new EnumMap<>(SettingType.class); protected final boolean updateInventory; - + public AuraDelayModule(String configPath, long defPlaceDelayMillis, long defBreakDelayMillis) { - super(configPath); + this(configPath, false, defPlaceDelayMillis, defBreakDelayMillis); + } + + public AuraDelayModule(String configPath, boolean defEnabled, long defPlaceDelayMillis, long defBreakDelayMillis) { + super(configPath, defEnabled); this.updateInventory = config.getBoolean(configPath + ".update-inventory-on-cancel", false, "Can help with desync but recommended to leave off unless you have issues."); for (SettingType settingType : SettingType.values()) { @@ -54,18 +64,10 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - cooldownSettings.forEach((settingType, cooldowns) -> { - cooldowns.placeCooldowns.clear(); - cooldowns.breakCooldowns.clear(); - }); + cooldownSettings.forEach((settingType, cooldowns) -> cooldowns.clear()); } protected boolean isOnCooldown(UUID uuid, Map cooldownMap, long delayNanos) { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java index e80f37b50..05d11b3dc 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java @@ -34,7 +34,7 @@ private void onPrePlayerAttackEntity(PrePlayerAttackEntityEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerInteract(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; // Need to right-click a block to place a crystal - if (event.getItem() == null || event.getItem().getType() != XMaterial.END_CRYSTAL.parseMaterial()) return; + if (event.getItem() == null || event.getItem().getType() != XMaterial.END_CRYSTAL.get()) return; for (Map.Entry entry : cooldownSettings.entrySet()) { if (entry.getKey() != SettingType.GLOBAL && entry.getKey().slot != event.getHand()) continue; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/AllayDupe.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/AllayDupe.java new file mode 100755 index 000000000..815608996 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/AllayDupe.java @@ -0,0 +1,62 @@ +package me.xginko.aef.modules.dupepreventions; + +import com.cryptomorin.xseries.XEntityType; +import me.xginko.aef.modules.AEFModule; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDropItemEvent; +import org.bukkit.event.entity.EntityPickupItemEvent; +import org.bukkit.event.vehicle.VehicleEnterEvent; + +public class AllayDupe extends AEFModule implements Listener { + + private final boolean dismount; + + public AllayDupe() { + super("dupe-preventions.allay-dupe", false, """ + Will prevent allays from entering vehicles to prevent a duplication exploit + confirmed working in 1.19.4."""); + this.dismount = config.getBoolean(configPath + ".dismount-premounted-allays", true); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onVehicleEnter(VehicleEnterEvent event) { + if (event.getEntered().getType() == XEntityType.ALLAY.get()) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntityPickupItem(EntityPickupItemEvent event) { + if (event.getEntityType() != XEntityType.ALLAY.get()) return; + + if (event.getEntity().isInsideVehicle()) { + event.setCancelled(true); + if (dismount) + event.getEntity().getScheduler().execute(plugin, event.getEntity()::leaveVehicle, null, 10); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntityDropItem(EntityDropItemEvent event) { + if (event.getEntityType() != XEntityType.ALLAY.get()) return; + + if (event.getEntity().isInsideVehicle()) { + event.setCancelled(true); + if (dismount) + event.getEntity().getScheduler().execute(plugin, event.getEntity()::leaveVehicle, null, 10); + } + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BookTitleDupe.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BookTitleDupe.java new file mode 100755 index 000000000..e037fe9d0 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BookTitleDupe.java @@ -0,0 +1,78 @@ +package me.xginko.aef.modules.dupepreventions; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.event.PacketListenerPriority; +import com.github.retrooper.packetevents.event.PacketReceiveEvent; +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; +import me.xginko.aef.modules.packets.PacketModule; + +import java.nio.charset.StandardCharsets; + +public class BookTitleDupe extends PacketModule { + + private final int titleLimit, pageLimit, pageCharLimit; + private final boolean log, kick; + + public BookTitleDupe() { + super("dupe-preventions.book-title-dupe", + PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_6) && + PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_21_2), + PacketListenerPriority.HIGHEST,""" + Relevant for 1.20.6 - 1.21: + Will prevent players from sending book packets with a too large title, + to get disconnected and their inventories restored."""); + boolean modernLimits = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2); + this.titleLimit = config.getInt(configPath + ".max-title-charlength", modernLimits ? 32 : 128); + this.pageLimit = config.getInt(configPath + ".max-pages", modernLimits ? 100 : 200); + this.pageCharLimit = config.getInt(configPath + ".max-page-charlength", modernLimits ? 1024 : 8192); + this.log = config.getBoolean(configPath + ".log", false); + this.kick = config.getBoolean(configPath + ".kick-player", false); + } + + @Override + public void onPacketReceive(PacketReceiveEvent event) { + if (event.getPacketType() != PacketType.Play.Client.EDIT_BOOK) return; + + if (isIllegalBookEdit(event)) { + event.setCancelled(true); + onCancel(log, kick, event.getUser()); + } + } + + private boolean isIllegalBookEdit(PacketReceiveEvent event) { + int slot = ByteBufHelper.readVarInt(event.getByteBuf()); + + int pageCount = ByteBufHelper.readVarInt(event.getByteBuf()); + + if (pageCount > pageLimit) { + return true; + } + + for (int i = 0; i < pageCount; ++i) { + if (isStringTooBig(event.getByteBuf(), pageCharLimit)) { + return true; + } + } + + if (ByteBufHelper.readByte(event.getByteBuf()) != 0) { + return isStringTooBig(event.getByteBuf(), titleLimit); + } + + return false; + } + + private boolean isStringTooBig(Object byteBuf, int charLimit) { + int strBufLen = ByteBufHelper.readVarInt(byteBuf); + + // Check if the received encoded string buffer length is shorter or longer than allowed + if (strBufLen < 0 || strBufLen > charLimit * 4) { + return true; + } + + // The received string length is longer than maximum allowed + return ByteBufHelper.toString(byteBuf, ByteBufHelper.readerIndex(byteBuf), strBufLen, StandardCharsets.UTF_8) + .length() > charLimit; + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/ChestedEntitiesInPortals.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/ChestedEntitiesInPortals.java index 6f66a62b1..1453c586f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/ChestedEntitiesInPortals.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/ChestedEntitiesInPortals.java @@ -14,8 +14,7 @@ public class ChestedEntitiesInPortals extends AEFModule implements Listener { public ChestedEntitiesInPortals() { - super("dupe-preventions.prevent-chested-living-entities-in-portals"); - config.addComment(configPath, """ + super("dupe-preventions.prevent-chested-living-entities-in-portals", false, """ Prevents entities that can carry chests from using portals to\s block some common dupe tactics.\s CAUTION: Will remove chests and their contents from a chested\s @@ -27,11 +26,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -39,9 +33,7 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityPortalEvent(EntityPortalEvent event) { // Does not fire on folia due to broken API - if (!EntityUtil.isChestableHorse(event.getEntity())) return; - - if (((ChestedHorse) event.getEntity()).isCarryingChest()) { + if (EntityUtil.isChestableHorse(event.getEntity()) && ((ChestedHorse) event.getEntity()).isCarryingChest()) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/ChestsOnEntities.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/ChestsOnEntities.java index e1177a262..0bd08cf57 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/ChestsOnEntities.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/ChestsOnEntities.java @@ -12,8 +12,7 @@ public class ChestsOnEntities extends AEFModule implements Listener { public ChestsOnEntities() { - super("dupe-preventions.prevent-chests-on-living-entities"); - config.addComment(configPath, """ + super("dupe-preventions.prevent-chests-on-living-entities", false, """ Prevent any possible dupes involving chested entities by making\s it impossible to put a chest on them.\s Only do this if you have reason to believe a dupe like that exists\s @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoriesOnLogout.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoriesOnLogout.java index c1010febf..48434ba6e 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoriesOnLogout.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoriesOnLogout.java @@ -14,8 +14,7 @@ public class CloseEntityInventoriesOnLogout extends AEFModule implements Listener { public CloseEntityInventoriesOnLogout() { - super("dupe-preventions.close-entity-inventories-on-player-disconnect"); - config.addComment(configPath, """ + super("dupe-preventions.close-entity-inventories-on-player-disconnect", false, """ Closes open inventories of entities that disappeared when the\s player riding it disconnects."""); } @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoryOnChunkUnload.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoryOnChunkUnload.java index c40811fe5..7afb9e5cf 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoryOnChunkUnload.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoryOnChunkUnload.java @@ -14,8 +14,7 @@ public class CloseEntityInventoryOnChunkUnload extends AEFModule implements Listener { public CloseEntityInventoryOnChunkUnload() { - super("dupe-preventions.close-entity-inventories-on-chunk-unload"); - config.addComment(configPath, """ + super("dupe-preventions.close-entity-inventories-on-chunk-unload", false, """ Closes open inventories of all entities that are in a chunk\s that will be unloaded."""); } @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraAtSpawn.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraAtSpawn.java index 2df18da9c..00373ae83 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraAtSpawn.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraAtSpawn.java @@ -2,11 +2,10 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.config.LanguageCache; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; import org.bukkit.Location; @@ -23,14 +22,11 @@ public class ElytraAtSpawn extends AEFModule implements Listener { private final double spawn_SpeedOldChunks, spawn_SpeedNewChunks, spawn_DenyElytraTPS; - private final boolean spawn_shouldCheckPermission, spawn_DenyElytra, spawn_DenyOnLowTPS, spawn_AlsoRemoveElytraOnLowTPS; + private final boolean spawn_DenyElytra, spawn_DenyOnLowTPS, spawn_AlsoRemoveElytraOnLowTPS; public ElytraAtSpawn() { - super("elytra.elytra-speed.At-Spawn"); - config.addComment(configPath + ".enable", + super("elytra.elytra-speed.At-Spawn", false, "Use separate values for players at spawn."); - this.spawn_shouldCheckPermission = config.getBoolean(configPath + ".use-bypass-permission", false, - "Can be slow with a lot of players. Enable only if needed."); this.spawn_DenyElytra = config.getBoolean(configPath + ".deny-elytra-usage", false); this.spawn_SpeedOldChunks = config.getDouble(configPath + ".speed-old-chunks", 1.0); this.spawn_SpeedNewChunks = config.getDouble(configPath + ".speed-new-chunks", 0.8); @@ -59,7 +55,7 @@ private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); if (!player.isGliding()) return; if (!event.hasExplicitlyChangedPosition()) return; - if (spawn_shouldCheckPermission && CachingPermTool.hasPermission(AEFPermission.BYPASS_ELYTRA, player)) return; + if (AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_ELYTRA.node()).toBoolean()) return; Location playerLoc = player.getLocation(); if (config.elytra_enable_netherceiling && LocationUtil.isNetherCeiling(playerLoc)) return; if (LocationUtil.getDistance2DTo00(playerLoc) > config.elytra_spawn_radius) return; @@ -77,7 +73,7 @@ private void onPlayerMove(PlayerMoveEvent event) { return; } - if (spawn_DenyOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= spawn_DenyElytraTPS) { + if (spawn_DenyOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= spawn_DenyElytraTPS) { if (config.elytra_teleport_back) player.teleportAsync(ElytraHelper.getInstance().getSetbackLocation(event)); else event.setCancelled(true); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraGlobal.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraGlobal.java index ca6462d70..31f2ef5fa 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraGlobal.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraGlobal.java @@ -2,11 +2,10 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.config.LanguageCache; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; import org.bukkit.Location; @@ -23,17 +22,11 @@ public class ElytraGlobal extends AEFModule implements Listener { private final double global_SpeedOldChunks, global_SpeedNewChunks, global_BurstSpeedOldChunks, global_BurstSpeedNewChunks, global_BurstOldChunk_TPS, global_BurstNewChunk_TPS, global_DenyElytraTPS; - private final boolean global_shouldCheckPermission, global_DenyElytra, global_EnableBursting, - global_DenyOnLowTPS, global_AlsoRemoveOnLowTPS; + private final boolean global_DenyElytra, global_EnableBursting, global_DenyOnLowTPS, global_AlsoRemoveOnLowTPS; public ElytraGlobal() { - super("elytra.elytra-speed.Global-Settings"); - config.addComment("elytra.elytra-speed", - "NOTE: Set nocheatplus horizontal elytra settings to 500 or higher."); - config.addComment(configPath + ".enable", + super("elytra.elytra-speed.Global-Settings", false, "Global settings. If nothing else is enabled, this will be used for all environments."); - this.global_shouldCheckPermission = config.getBoolean(configPath + ".use-bypass-permission", false, - "Can be slow with a lot of players. Enable only if needed."); this.global_DenyElytra = config.getBoolean(configPath + ".deny-elytra-usage", false); this.global_SpeedOldChunks = config.getDouble(configPath + ".speed-old-chunks", 1.81); this.global_SpeedNewChunks = config.getDouble(configPath + ".speed-new-chunks", 1.81); @@ -52,11 +45,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.elytra_enable_global; - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -67,7 +55,7 @@ private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); if (!player.isGliding()) return; if (!event.hasExplicitlyChangedPosition()) return; - if (global_shouldCheckPermission && CachingPermTool.hasPermission(AEFPermission.BYPASS_ELYTRA, player)) return; + if (AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_ELYTRA.node()).toBoolean()) return; Location playerLoc = player.getLocation(); if (config.elytra_enable_netherceiling && LocationUtil.isNetherCeiling(playerLoc)) return; if (config.elytra_enable_at_spawn && LocationUtil.getDistance2DTo00(playerLoc) <= config.elytra_spawn_radius) return; @@ -84,7 +72,7 @@ private void onPlayerMove(PlayerMoveEvent event) { return; } - if (global_DenyOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= global_DenyElytraTPS) { + if (global_DenyOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= global_DenyElytraTPS) { if (config.elytra_teleport_back) player.teleportAsync(ElytraHelper.getInstance().getSetbackLocation(event)); else event.setCancelled(true); @@ -112,7 +100,7 @@ private void onPlayerMove(PlayerMoveEvent event) { if (ElytraHelper.getInstance().isInNewChunks(player)) { // Speed New Chunks - if (global_EnableBursting && AnarchyExploitFixes.getTickReporter().getTPS() >= global_BurstNewChunk_TPS) { + if (global_EnableBursting && AnarchyExploitFixes.tickReporter().getTPS() >= global_BurstNewChunk_TPS) { // Burst Speed New Chunks if (flySpeed > global_BurstSpeedNewChunks) { if (config.elytra_teleport_back) player.teleportAsync(ElytraHelper.getInstance().getSetbackLocation(event)); @@ -195,7 +183,7 @@ private void onPlayerMove(PlayerMoveEvent event) { } } else { // Speed Old Chunks - if (global_EnableBursting && AnarchyExploitFixes.getTickReporter().getTPS() >= global_BurstOldChunk_TPS) { + if (global_EnableBursting && AnarchyExploitFixes.tickReporter().getTPS() >= global_BurstOldChunk_TPS) { // Burst Speed Old Chunks if (flySpeed > global_BurstSpeedOldChunks) { if (config.elytra_teleport_back) player.teleportAsync(ElytraHelper.getInstance().getSetbackLocation(event)); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraHelper.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraHelper.java index cc8474676..65790f872 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraHelper.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraHelper.java @@ -32,17 +32,16 @@ public class ElytraHelper extends AEFModule implements Runnable, PacketListener, Listener { private static ElytraHelper instance; - private final Map playerDataMap; - private final PacketListenerAbstract packetListener; + private final long speed_as_ticks = config.elytra_speed_calc_period / 50L; + + private Map playerDataMap; + private PacketListenerAbstract packetListener; private ScheduledExecutorService executorService; private ScheduledFuture scheduledTask; - private final long speed_as_ticks = config.elytra_speed_calc_period / 50L; public ElytraHelper() { super("elytra.elytra-speed"); instance = this; - playerDataMap = new ConcurrentHashMap<>(); - packetListener = asAbstract(PacketListenerPriority.MONITOR); } public static ElytraHelper getInstance() { @@ -51,6 +50,8 @@ public static ElytraHelper getInstance() { @Override public void enable() { + playerDataMap = new ConcurrentHashMap<>(); + packetListener = asAbstract(PacketListenerPriority.MONITOR); plugin.getServer().getPluginManager().registerEvents(this, plugin); PacketEvents.getAPI().getEventManager().registerListener(packetListener); executorService = Executors.newScheduledThreadPool(1); @@ -66,9 +67,22 @@ public boolean shouldEnable() { @Override public void disable() { HandlerList.unregisterAll(this); - PacketEvents.getAPI().getEventManager().unregisterListener(packetListener); - if (scheduledTask != null) scheduledTask.cancel(true); - if (executorService != null) executorService.shutdown(); + if (packetListener != null) { + PacketEvents.getAPI().getEventManager().unregisterListener(packetListener); + packetListener = null; + } + if (playerDataMap != null) { + playerDataMap.clear(); + playerDataMap = null; + } + if (scheduledTask != null) { + scheduledTask.cancel(true); + scheduledTask = null; + } + if (executorService != null) { + executorService.shutdownNow(); + executorService = null; + } } @Override diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraOnCeiling.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraOnCeiling.java index 47fc53999..eed2cb25f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraOnCeiling.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraOnCeiling.java @@ -2,11 +2,10 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.config.LanguageCache; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; import org.bukkit.Location; @@ -23,15 +22,11 @@ public class ElytraOnCeiling extends AEFModule implements Listener { private final double ceiling_SpeedOldChunks, ceiling_SpeedNewChunks, ceiling_BurstSpeedOldChunks, ceiling_BurstSpeedNewChunks, ceiling_BurstOldChunk_TPS, ceiling_BurstNewChunk_TPS, ceiling_DenyElytraTPS; - private final boolean ceiling_shouldCheckPermission, - ceiling_DenyElytra, ceiling_EnableBursting, ceiling_DenyOnLowTPS, ceiling_AlsoRemoveOnLowTPS; + private final boolean ceiling_DenyElytra, ceiling_EnableBursting, ceiling_DenyOnLowTPS, ceiling_AlsoRemoveOnLowTPS; public ElytraOnCeiling() { - super("elytra.elytra-speed.Nether-Ceiling"); - config.addComment(configPath + ".enable", + super("elytra.elytra-speed.Nether-Ceiling", false, "Use separate values for players above the nether ceiling."); - this.ceiling_shouldCheckPermission = config.getBoolean(configPath + ".use-bypass-permission", false, - "Can be slow with a lot of players. Enable only if needed."); this.ceiling_DenyElytra = config.getBoolean(configPath + ".deny-elytra-usage", false); this.ceiling_SpeedOldChunks = config.getDouble(configPath + ".speed-old-chunks", 0.5); this.ceiling_SpeedNewChunks = config.getDouble(configPath + ".speed-new-chunks", 0.5); @@ -65,7 +60,7 @@ private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); if (!player.isGliding()) return; if (!event.hasExplicitlyChangedPosition()) return; - if (ceiling_shouldCheckPermission && CachingPermTool.hasPermission(AEFPermission.BYPASS_ELYTRA, player)) return; + if (AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_ELYTRA.node()).toBoolean()) return; Location playerLoc = player.getLocation(); if (!LocationUtil.isNetherCeiling(playerLoc)) return; @@ -81,7 +76,7 @@ private void onPlayerMove(PlayerMoveEvent event) { return; } - if (ceiling_DenyOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= ceiling_DenyElytraTPS) { + if (ceiling_DenyOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= ceiling_DenyElytraTPS) { if (config.elytra_teleport_back) player.teleportAsync(ElytraHelper.getInstance().getSetbackLocation(event)); else event.setCancelled(true); @@ -110,7 +105,7 @@ private void onPlayerMove(PlayerMoveEvent event) { if (ElytraHelper.getInstance().isInNewChunks(player)) { // Speed New Chunks - if (ceiling_EnableBursting && AnarchyExploitFixes.getTickReporter().getTPS() >= ceiling_BurstNewChunk_TPS) { + if (ceiling_EnableBursting && AnarchyExploitFixes.tickReporter().getTPS() >= ceiling_BurstNewChunk_TPS) { // Burst Speed New Chunks if (flySpeed > ceiling_BurstSpeedNewChunks) { if (config.elytra_teleport_back) player.teleportAsync(ElytraHelper.getInstance().getSetbackLocation(event)); @@ -193,7 +188,7 @@ private void onPlayerMove(PlayerMoveEvent event) { } } else { // Speed Old Chunks - if (ceiling_EnableBursting && AnarchyExploitFixes.getTickReporter().getTPS() >= ceiling_BurstOldChunk_TPS) { + if (ceiling_EnableBursting && AnarchyExploitFixes.tickReporter().getTPS() >= ceiling_BurstOldChunk_TPS) { // Burst Speed Old Chunks if (flySpeed > ceiling_BurstSpeedOldChunks) { if (config.elytra_teleport_back) player.teleportAsync(ElytraHelper.getInstance().getSetbackLocation(event)); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraPacketFly.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraPacketFly.java index 0e4da8f4e..36443bf64 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraPacketFly.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/elytra/ElytraPacketFly.java @@ -20,14 +20,15 @@ public class ElytraPacketFly extends AEFModule implements Listener { - private final Cache elytraOpenCounts; + private final long durationMillis; private final int maxElytraOpensPerTime; private final boolean notify, kickPlayer; + private Cache elytraOpenCounts; + public ElytraPacketFly() { - super("elytra.packet-elytra-fly"); - config.addComment(configPath + ".patch-packet-elytra-fly", """ - Patches the future/rusherhack/kamiblue 2b2t elytra fly exploit."""); + super("elytra.packet-elytra-fly", false, """ + Cheap patch for future/rusherhack/kamiblue 2b2t elytra fly exploit."""); this.maxElytraOpensPerTime = Math.max(1, config.getInt(configPath + ".max-elytra-opens-per-time", 25, """ The fly exploit causes the player to constantly toggle gliding.\s If too many glide toggles occur within a timeframe, they are\s @@ -35,10 +36,8 @@ public ElytraPacketFly() { Still may trigger false positives when players are jumping and\s sprinting with elytra equipped, so recommended to play around\s with the values.""")); - this.elytraOpenCounts = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(Math.max(1, - config.getInt(configPath + ".time-in-seconds", 8, """ - Time in seconds a elytra open count will be remembered by the plugin.""") - ))).build(); + this.durationMillis = Math.max(1, config.getInt(configPath + ".time-in-seconds", 8, """ + Time in seconds a elytra open count will be remembered by the plugin.""")); this.notify = config.getBoolean(configPath + ".notify-player-to-disable-packetfly", true, """ Configure message in lang folder."""); this.kickPlayer = config.getBoolean(configPath + ".kick-instead-of-remove-elytra", false, """ @@ -48,17 +47,17 @@ public ElytraPacketFly() { @Override public void enable() { + elytraOpenCounts = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(durationMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".patch-packet-elytra-fly", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (elytraOpenCounts != null) { + elytraOpenCounts.invalidateAll(); + elytraOpenCounts.cleanUp(); + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/BannedItemNames.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/BannedItemNames.java index 085b417f0..caeff0016 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/BannedItemNames.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/BannedItemNames.java @@ -1,10 +1,10 @@ package me.xginko.aef.modules.illegals.items; import com.destroystokyo.paper.event.inventory.PrepareResultEvent; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; -import me.xginko.aef.utils.CachingPermTool; +import me.xginko.aef.AnarchyExploitFixes; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.Material; import org.bukkit.event.EventHandler; @@ -31,13 +31,12 @@ public class BannedItemNames extends IllegalItemModule { private final boolean delete; public BannedItemNames() { - super("illegals.banned-item-names", AEFPermission.BYPASS_ILLEGAL_BANNEDNAME); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Resets an item's name (or deletes the item) if it matches one of\n" + - "the configured regexes.\n" + - "Regexes can be complex. Use a tool like https://regex101.com/ or\n" + - "ChatGPT for good results."); + super("illegals.banned-item-names", false, AEFPermission.BYPASS_ILLEGAL_BANNEDNAME, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_BANNEDNAME.node() + "\n" + + "Resets an item's name (or deletes the item) if it matches one of\n" + + "the configured regexes.\n" + + "Regexes can be complex. Use a tool like https://regex101.com/ or\n" + + "ChatGPT for good results."); this.delete = config.getBoolean(configPath + ".delete-item", false, "Will delete the item instead of resetting the name."); this.bannedRegex = config.getList(configPath + ".regex", List.of("(?i)illegalstring")) @@ -57,12 +56,16 @@ public BannedItemNames() { }) .filter(Objects::nonNull) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); - if (handling == IllegalHandling.STRICT) { + if (illegalHandling == IllegalHandling.STRICT) { // Add listener for preview in anvil (for example) optionalListeners.add(new Listener() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPrepareResult(PrepareResultEvent event) { - if (CachingPermTool.hasPermission(bypassPermission, event.getView().getPlayer())) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getView().getPlayer().getUniqueId())) { + return; + } + + if (AnarchyExploitFixes.permissions().permissionValue(event.getView().getPlayer(), bypassPermission.node()).toBoolean()) return; ItemStack resultItem = event.getResult(); if (legalityOf(resultItem) == ItemLegality.ILLEGAL) { @@ -74,11 +77,6 @@ private void onPrepareResult(PrepareResultEvent event) { } } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if ( @@ -103,7 +101,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality == ItemLegality.ILLEGAL) { if (delete) { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/BannedMaterials.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/BannedMaterials.java index 838dfd9d0..4535bf74a 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/BannedMaterials.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/BannedMaterials.java @@ -1,9 +1,9 @@ package me.xginko.aef.modules.illegals.items; import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -23,9 +23,8 @@ public class BannedMaterials extends IllegalItemModule { private final boolean checkStored; public BannedMaterials() { - super("illegals.ban-specific-materials", AEFPermission.BYPASS_ILLEGAL_BANNEDMATERIAL); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.ban-specific-materials", false, AEFPermission.BYPASS_ILLEGAL_BANNEDMATERIAL, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_BANNEDMATERIAL.node() + "\n" + "Prevents usage of or deletes items with material that you do not want\n" + "your players to be able to use.\n" + "Useful if your players have blocks that shouldn't be obtainable in survival."); @@ -44,7 +43,7 @@ public BannedMaterials() { XMaterial.NETHER_PORTAL, XMaterial.LIGHT) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .map(Enum::name) .collect(Collectors.toList()); this.bannedMaterials = config.getList(configPath + ".banned-materials", defaults) @@ -61,11 +60,6 @@ public BannedMaterials() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null) { @@ -85,7 +79,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/IllegalItemModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/IllegalItemModule.java index b0edc56e1..7c67a365f 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/IllegalItemModule.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/IllegalItemModule.java @@ -1,19 +1,20 @@ package me.xginko.aef.modules.illegals.items; +import com.cryptomorin.xseries.XMaterial; import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import io.papermc.paper.event.player.PrePlayerAttackEntityEvent; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.models.ExpiringSet; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Chunk; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.EntityType; @@ -26,15 +27,16 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryInteractEvent; -import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.PlayerAttemptPickupItemEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; @@ -45,6 +47,7 @@ import java.time.Duration; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -52,15 +55,21 @@ public abstract class IllegalItemModule extends AEFModule implements Listener { protected final AEFPermission bypassPermission; - protected final IllegalHandling handling; + protected final IllegalHandling illegalHandling; + protected final boolean guiPluginsSupported; + protected final Set optionalListeners; - private final Cache, ExpiringSet> listenerCooldowns; - private final Function, @PolyNull ExpiringSet> createIfAbsent; + protected final Cache, ExpiringSet> listenerCooldowns; + protected final Function, @PolyNull ExpiringSet> createIfAbsent; public IllegalItemModule(String configPath, AEFPermission bypassPermission) { - super(configPath); + this(configPath, false, bypassPermission, null); + } + + public IllegalItemModule(String configPath, boolean defEnabled, AEFPermission bypassPermission, String comment) { + super(configPath, defEnabled, comment); this.bypassPermission = bypassPermission; - this.optionalListeners = new HashSet<>(); + this.optionalListeners = new HashSet<>(6); String configuredHandling = config.getString(configPath + ".handling", IllegalHandling.PREVENT_USE_ONLY.name(), "Available options:\n" + Arrays.stream(IllegalHandling.values()) @@ -73,15 +82,15 @@ public IllegalItemModule(String configPath, AEFPermission bypassPermission) { handling = IllegalHandling.PREVENT_USE_ONLY; warn("Handling option '" + configuredHandling + "' not recognized. Defaulting to " + handling.name()); } - this.handling = handling; + this.illegalHandling = handling; - final boolean guiPluginsSupported = config.getBoolean(configPath + ".gui-plugins-supported", false, """ + this.guiPluginsSupported = config.getBoolean(configPath + ".gui-plugins-supported", false, """ Enable this if you have problems with the plugin removing items from chest guis."""); - if (this.handling == IllegalHandling.STRICT) { + if (this.illegalHandling == IllegalHandling.STRICT) { optionalListeners.add(new Listener() { - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) private void onInventoryOpen(InventoryOpenEvent event) { - if (CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; // Check if the inventory is connected to a location in the game. If it is not, // it was very likely created by a plugin if (!guiPluginsSupported || event.getInventory().getLocation() != null) { @@ -96,13 +105,12 @@ private void onInventoryOpen(InventoryOpenEvent event) { if (config.getBoolean(configPath + ".prevent-hopper32k-mechanic", false, """ Prevents Hopper32k mechanic of placing a shulker containing illegals on top\s of a hopper, then using the illegal out of the hopper's inventory.\s - WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource\s - intense as the event fires in high frequencies as soon as players start using\s - farms or item sorters. Recommended to leave off if not necessary.""")) { + No longer hooks into InventoryMoveItemEvent and is therefore way less laggy.""")) { optionalListeners.add(new Listener() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onItemGoesThroughHopper(InventoryMoveItemEvent event) { - if (legalityOf(event.getItem()) != ItemLegality.LEGAL) { + private void onPlayerItemHeld(PlayerItemHeldEvent event) { // Fired when a hot bar item selection changes + if (legalityOf(event.getPlayer().getInventory().getItem(event.getNewSlot())) != ItemLegality.LEGAL + || legalityOf(event.getPlayer().getInventory().getItem(event.getPreviousSlot())) != ItemLegality.LEGAL) { event.setCancelled(true); } } @@ -119,11 +127,13 @@ private void onItemGoesThroughHopper(InventoryMoveItemEvent event) { to handle items separately."""); if (checkOnChunkload) { optionalListeners.add(new Listener() { - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) private void onChunkLoad(ChunkLoadEvent event) { if (event.isNewChunk()) return; Chunk chunk = event.getChunk(); + if (ChunkUtil.isRetrievalUnsafe(chunk)) return; + final int minY = event.getWorld().getMinHeight(); final int maxY = event.getWorld().getMaxHeight(); @@ -135,7 +145,7 @@ private void onChunkLoad(ChunkLoadEvent event) { if (removeContainers) { if (legalityOf(((InventoryHolder) block.getState()).getInventory()) != ItemLegality.LEGAL) - block.setType(Material.AIR, false); + block.setType(XMaterial.AIR.get(), false); } else { BlockState blockState = block.getState(false); for (ItemStack itemStack : ((InventoryHolder) blockState).getInventory()) @@ -172,6 +182,12 @@ public void disable() { HandlerList.unregisterAll(this); optionalListeners.forEach(HandlerList::unregisterAll); optionalListeners.clear(); + for (Map.Entry, ExpiringSet> entry : listenerCooldowns.asMap().entrySet()) { + entry.getValue().clear(); + entry.getValue().cleanUp(); + } + listenerCooldowns.invalidateAll(); + listenerCooldowns.cleanUp(); } public ItemLegality legalityOf(@Nullable Iterable itemStacks) { @@ -188,21 +204,27 @@ public ItemLegality legalityOf(@Nullable Iterable itemStacks) { return ItemLegality.LEGAL; } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerItemConsume(PlayerItemConsumeEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + if (legalityOf(event.getItem()) != ItemLegality.LEGAL) { event.setCancelled(true); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onBlockDispense(BlockDispenseEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getBlock().getLocation())) { event.setCancelled(true); return; @@ -214,29 +236,38 @@ public void onBlockDispense(BlockDispenseEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerArmorChange(PlayerArmorChangeEvent event) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // Cant cancel this event + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // Cant cancel this event - if (!CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (!AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) { handleItem(event.getNewItem(), legalityOf(event.getNewItem())); handleItem(event.getOldItem(), legalityOf(event.getOldItem())); } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onInventoryClick(InventoryClickEvent event) { - if (CachingPermTool.hasPermission(bypassPermission, event.getWhoClicked())) return; + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (guiPluginsSupported && event.getInventory().getLocation() == null) return; + if (event.getClick() == ClickType.DROP || event.getClick() == ClickType.CONTROL_DROP + || event.getClick() == ClickType.WINDOW_BORDER_LEFT || event.getClick() == ClickType.WINDOW_BORDER_RIGHT) { + return; + } if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getWhoClicked().getUniqueId())) { event.setCancelled(true); return; } - ItemLegality clickedLegality = legalityOf(event.getCurrentItem()); + if (AnarchyExploitFixes.permissions().permissionValue(event.getWhoClicked(), bypassPermission.node()).toBoolean()) return; + + ItemStack currentItem = event.getCurrentItem(); + ItemLegality clickedLegality = legalityOf(currentItem); if (clickedLegality != ItemLegality.LEGAL) { event.setCancelled(true); - handleItem(event.getCurrentItem(), clickedLegality); + handleItem(currentItem, clickedLegality); + event.setCurrentItem(currentItem); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getWhoClicked().getUniqueId()); } @@ -248,15 +279,18 @@ public void onInventoryClick(InventoryClickEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onInventoryInteract(InventoryInteractEvent event) { - if (CachingPermTool.hasPermission(bypassPermission, event.getWhoClicked())) return; + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) + public void onInventoryDrag(InventoryDragEvent event) { + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (guiPluginsSupported && event.getInventory().getLocation() == null) return; if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getWhoClicked().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getWhoClicked(), bypassPermission.node()).toBoolean()) return; + for (ItemStack invItem : event.getInventory()) { ItemLegality invItemLegality = legalityOf(invItem); if (invItemLegality != ItemLegality.LEGAL) { @@ -267,16 +301,20 @@ public void onInventoryInteract(InventoryInteractEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPrePlayerAttackEntity(PrePlayerAttackEntityEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack mainHandItem = event.getPlayer().getInventory().getItemInMainHand(); final ItemLegality mainHandLegality = legalityOf(mainHandItem); - if (mainHandLegality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (mainHandLegality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(mainHandItem, mainHandLegality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); @@ -284,15 +322,17 @@ public void onPrePlayerAttackEntity(PrePlayerAttackEntityEvent event) { ItemStack offHandItem = event.getPlayer().getInventory().getItemInOffHand(); final ItemLegality offHandLegality = legalityOf(offHandItem); - if (offHandLegality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (offHandLegality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(offHandItem, offHandLegality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (event.getDamager().getType() == EntityType.PLAYER) { final Player player = (Player) event.getDamager(); @@ -301,9 +341,11 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { return; } + if (AnarchyExploitFixes.permissions().permissionValue(player, bypassPermission.node()).toBoolean()) return; + ItemStack mainHandItem = player.getInventory().getItemInMainHand(); final ItemLegality mainHandLegality = legalityOf(mainHandItem); - if (mainHandLegality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, player)) { + if (mainHandLegality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(mainHandItem, mainHandLegality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(player.getUniqueId()); @@ -311,7 +353,7 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { ItemStack offHandItem = player.getInventory().getItemInOffHand(); final ItemLegality offHandLegality = legalityOf(offHandItem); - if (offHandLegality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, player)) { + if (offHandLegality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(offHandItem, offHandLegality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(player.getUniqueId()); @@ -322,7 +364,7 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { if (EntityUtil.isLivingEntity(event.getDamager())) { if (legalityOf(((LivingEntity) event.getDamager()).getActiveItem()) != ItemLegality.LEGAL) { event.setCancelled(true); - if (handling != IllegalHandling.PREVENT_USE_ONLY) + if (illegalHandling != IllegalHandling.PREVENT_USE_ONLY) event.getDamager().getScheduler().execute(plugin, event.getDamager()::remove, null, 1L); return; } @@ -331,22 +373,26 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { if (EntityUtil.isInventoryHolder(event.getDamager())) { if (legalityOf(((InventoryHolder) event.getDamager()).getInventory()) != ItemLegality.LEGAL) { event.setCancelled(true); - if (handling != IllegalHandling.PREVENT_USE_ONLY) + if (illegalHandling != IllegalHandling.PREVENT_USE_ONLY) event.getDamager().getScheduler().execute(plugin, event.getDamager()::remove, null, 1L); } } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerAttemptPickupItem(PlayerAttemptPickupItemEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack pickUpItem = event.getItem().getItemStack(); final ItemLegality legality = legalityOf(pickUpItem); - if (legality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (legality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(pickUpItem, legality); event.getItem().setItemStack(pickUpItem); @@ -354,16 +400,20 @@ public void onPlayerAttemptPickupItem(PlayerAttemptPickupItemEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerDropItem(PlayerDropItemEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack droppedItem = event.getItemDrop().getItemStack(); final ItemLegality legality = legalityOf(droppedItem); - if (legality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (legality != ItemLegality.LEGAL) { handleItem(droppedItem, legality); event.getItemDrop().setItemStack(droppedItem); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); @@ -372,30 +422,38 @@ public void onPlayerDropItem(PlayerDropItemEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerInteract(PlayerInteractEvent event) { + if (event.useItemInHand() == Event.Result.DENY && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack interactItem = event.getItem(); final ItemLegality legality = legalityOf(interactItem); - if (legality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (legality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(interactItem, legality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack handItem = event.getPlayer().getInventory().getItem(event.getHand()); final ItemLegality legality = legalityOf(handItem); - if (legality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (legality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(handItem, legality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/IllegalPotions.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/IllegalPotions.java index 2383479cf..77cd31dfe 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/IllegalPotions.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/IllegalPotions.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.illegals.items; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; import org.bukkit.inventory.ItemStack; @@ -15,19 +15,13 @@ public class IllegalPotions extends IllegalItemModule { private final boolean checkStored; public IllegalPotions() { - super("illegals.potions", AEFPermission.BYPASS_ILLEGAL_POTIONS); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Prevents usage of or reverts items with any attribute modifiers\n" + - "or item flags."); + super("illegals.potions", false, AEFPermission.BYPASS_ILLEGAL_POTIONS, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_POTIONS.node() + "\n" + + "Prevents usage of or reverts items with any attribute modifiers\n" + + "or item flags."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || !MaterialUtil.POTIONS.contains(itemStack.getType()) || !itemStack.hasItemMeta()) { @@ -48,7 +42,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class switch (legality) { case CONTAINS_ILLEGAL -> itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/InvalidStackSize.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/InvalidStackSize.java index 9e8694eb0..0c239c712 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/InvalidStackSize.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/InvalidStackSize.java @@ -1,8 +1,9 @@ package me.xginko.aef.modules.illegals.items; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -21,15 +22,15 @@ public class InvalidStackSize extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public InvalidStackSize() { - super("illegals.illegally-stacked-items", AEFPermission.BYPASS_ILLEGAL_OVERSTACKED); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Prevents usage of or reverts items with a higher or lower\n" + - "stack size than their vanilla limit."); + super("illegals.illegally-stacked-items", false, AEFPermission.BYPASS_ILLEGAL_OVERSTACKED, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_OVERSTACKED.node() + "\n" + + "Prevents usage of or reverts items with a higher or lower\n" + + "stack size than their vanilla limit."); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", false); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", true); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", List.of("TOTEM_OF_UNDYING")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + List.of(XMaterial.TOTEM_OF_UNDYING.get().name())) .stream() .map(configuredType -> { try { @@ -43,11 +44,6 @@ public InvalidStackSize() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || itemStack.getType().isAir()) { @@ -69,7 +65,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class switch (legality) { case ILLEGAL -> { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/ItemAttributes.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/ItemAttributes.java index df8637b82..1ce957062 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/ItemAttributes.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/ItemAttributes.java @@ -1,8 +1,9 @@ package me.xginko.aef.modules.illegals.items; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemFlag; @@ -23,15 +24,15 @@ public class ItemAttributes extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public ItemAttributes() { - super("illegals.attribute-modifiers", AEFPermission.BYPASS_ILLEGAL_ATTRIBUTES); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.attribute-modifiers", false, AEFPermission.BYPASS_ILLEGAL_ATTRIBUTES, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_ATTRIBUTES.node() + "\n" + "Prevents usage of or reverts items with any attribute modifiers\n" + "or item flags."); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", false); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", true); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", List.of("TOTEM_OF_UNDYING")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + List.of(XMaterial.TOTEM_OF_UNDYING.get().name())) .stream() .map(configuredType -> { try { @@ -45,11 +46,6 @@ public ItemAttributes() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || itemStack.getType().isAir() || !itemStack.hasItemMeta()) { @@ -72,7 +68,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class switch (legality) { case CONTAINS_ILLEGAL -> itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/PlayerHeads.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/PlayerHeads.java index 4fe7f19e7..6f3a5ea2c 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/PlayerHeads.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/PlayerHeads.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.illegals.items; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; import org.bukkit.inventory.ItemStack; @@ -14,19 +14,13 @@ public class PlayerHeads extends IllegalItemModule { private final boolean checkStored; public PlayerHeads() { - super("illegals.ban-player-heads", AEFPermission.BYPASS_ILLEGAL_PLAYERHEAD); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.ban-player-heads", false, AEFPermission.BYPASS_ILLEGAL_PLAYERHEAD, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_PLAYERHEAD.node() + "\n" + "Deletes or prevents usage of player heads."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false, "Will delete shulker/bundle if they contain any player heads."); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null) { @@ -46,7 +40,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/SpawnEggs.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/SpawnEggs.java index 2ffeb7c01..4df3c36b8 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/SpawnEggs.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/SpawnEggs.java @@ -2,9 +2,9 @@ import com.cryptomorin.xseries.XMaterial; import com.destroystokyo.paper.MaterialTags; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -23,15 +23,14 @@ public class SpawnEggs extends IllegalItemModule { private final boolean checkStored; public SpawnEggs() { - super("illegals.ban-spawn-eggs", AEFPermission.BYPASS_ILLEGAL_SPAWNEGG); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.ban-spawn-eggs", false, AEFPermission.BYPASS_ILLEGAL_SPAWNEGG, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_SPAWNEGG.node() + "\n" + "Deletes or prevents usage of spawn eggs."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false, """ If remove-spawn-eggs is set to true Will delete shulker/bundle\s should they contain any spawneggs."""); this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", - Collections.singletonList(XMaterial.VILLAGER_SPAWN_EGG.parseMaterial().name())) + Collections.singletonList(XMaterial.VILLAGER_SPAWN_EGG.get().name())) .stream() .map(configuredType -> { try { @@ -45,11 +44,6 @@ public SpawnEggs() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || whitelistedTypes.contains(itemStack.getType())) { @@ -69,7 +63,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/Unbreakables.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/Unbreakables.java index 895d40224..5eee59393 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/Unbreakables.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/Unbreakables.java @@ -1,8 +1,9 @@ package me.xginko.aef.modules.illegals.items; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -23,19 +24,19 @@ public class Unbreakables extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public Unbreakables() { - super("illegals.revert-unbreakables", AEFPermission.BYPASS_ILLEGAL_UNBREAKABLE); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Deletes and prevents usage of unbreakable items.\n" + - "This can be anything from items with illegal damage attributes to\n" + - "Metadata/NBT tags.\n" + - "Note: Due to the limitations of the API, we can only fully prevent\n" + - "usage of these items by deleting them."); + super("illegals.revert-unbreakables", false, AEFPermission.BYPASS_ILLEGAL_UNBREAKABLE, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_UNBREAKABLE.node() + "\n" + + "Deletes and prevents usage of unbreakable items.\n" + + "This can be anything from items with illegal damage attributes to\n" + + "Metadata/NBT tags.\n" + + "Note: Due to the limitations of the API, we can only fully prevent\n" + + "usage of these items by deleting them."); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", false); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false, "Will delete shulkers and bundles if they contain unbreakables."); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", List.of("DIAMOND_CHESTPLATE")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + List.of(XMaterial.DIAMOND_CHESTPLATE.get().name())) .stream() .map(configuredType -> { try { @@ -49,11 +50,6 @@ public Unbreakables() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || itemStack.getType().isAir() || !itemStack.hasItemMeta()) { @@ -89,7 +85,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; switch (legality) { case CONTAINS_ILLEGAL -> itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/HigherEnchants.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/HigherEnchants.java index d1bab08d6..56d83a1aa 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/HigherEnchants.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/HigherEnchants.java @@ -1,8 +1,10 @@ package me.xginko.aef.modules.illegals.items.enchantments; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XEnchantment; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; @@ -16,6 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -25,27 +28,30 @@ public class HigherEnchants extends IllegalItemModule { private final Set whitelistedTypes; private final boolean useWhitelist, blacklistMode, checkStored, onlySomeEnchants; - @SuppressWarnings("deprecation") public HigherEnchants() { - super("illegals.enchantments.higher-enchants", AEFPermission.BYPASS_ILLEGAL_ENCHANT_HIGHER); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.enchantments.higher-enchants", false, AEFPermission.BYPASS_ILLEGAL_ENCHANT_HIGHER, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_ENCHANT_HIGHER.node() + "\n" + "Reverts or prevents usage of ItemStacks with Enchantments higher\n" + "than the natural, in vanilla survival obtainable level (aka 32ks / 255s)."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.onlySomeEnchants = config.getBoolean(configPath + ".only-specific-enchants", false); - this.specificEnchants = config.getList(configPath + ".specific-enchants", List.of("DIG_SPEED")) + this.specificEnchants = config.getList(configPath + ".specific-enchants", + List.of(XEnchantment.EFFICIENCY.get().getName())) .stream() .map(configuredEnchant -> { - final Enchantment enchantment = Enchantment.getByName(configuredEnchant); - if (enchantment == null) notRecognized(Enchantment.class, configuredEnchant); - return enchantment; + Optional enchantment = XEnchantment.of(configuredEnchant); + if (enchantment.isEmpty()) { + notRecognized(Enchantment.class, configuredEnchant); + return null; + } + return enchantment.get().get(); }) .filter(Objects::nonNull) .collect(Collectors.toCollection(HashSet::new)); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", true); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", List.of("GOLDEN_APPLE")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + List.of(XMaterial.GOLDEN_APPLE.get().name())) .stream() .map(configuredType -> { try { @@ -59,11 +65,6 @@ public HigherEnchants() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || itemStack.getType().isAir()) { @@ -90,7 +91,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { if (legality == ItemLegality.LEGAL) return; - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality == ItemLegality.CONTAINS_ILLEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/InapplicableEnchants.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/InapplicableEnchants.java index dde4d37d1..7d26c947c 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/InapplicableEnchants.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/InapplicableEnchants.java @@ -1,8 +1,9 @@ package me.xginko.aef.modules.illegals.items.enchantments; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; @@ -24,16 +25,16 @@ public class InapplicableEnchants extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public InapplicableEnchants() { - super("illegals.enchantments.inapplicable-enchants", AEFPermission.BYPASS_ILLEGAL_ENCHANT_INAPPLICABLE); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.enchantments.inapplicable-enchants", false, AEFPermission.BYPASS_ILLEGAL_ENCHANT_INAPPLICABLE, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_ENCHANT_INAPPLICABLE.node() + "\n" + "Reverts or prevents usage of ItemStacks with Enchantments that\n" + "cannot be applied to that ItemStack in vanilla survival minecraft.\n" + "Examples: A helmet with sharpness or a block of stone with fortune."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", true); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", List.of("GOLDEN_APPLE")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + List.of(XMaterial.GOLDEN_APPLE.get().name())) .stream() .map(configuredType -> { try { @@ -47,11 +48,6 @@ public InapplicableEnchants() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || itemStack.getType().isAir()) { @@ -76,7 +72,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { if (legality == ItemLegality.LEGAL) return; - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality == ItemLegality.CONTAINS_ILLEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/IncompatibleEnchants.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/IncompatibleEnchants.java index 4a2f981e6..0153fd43b 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/IncompatibleEnchants.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/IncompatibleEnchants.java @@ -1,8 +1,11 @@ package me.xginko.aef.modules.illegals.items.enchantments; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XEnchantment; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; @@ -17,27 +20,6 @@ import java.util.Set; import java.util.stream.Collectors; -import static com.cryptomorin.xseries.XEnchantment.BANE_OF_ARTHROPODS; -import static com.cryptomorin.xseries.XEnchantment.BINDING_CURSE; -import static com.cryptomorin.xseries.XEnchantment.BLAST_PROTECTION; -import static com.cryptomorin.xseries.XEnchantment.CHANNELING; -import static com.cryptomorin.xseries.XEnchantment.DEPTH_STRIDER; -import static com.cryptomorin.xseries.XEnchantment.FIRE_PROTECTION; -import static com.cryptomorin.xseries.XEnchantment.FORTUNE; -import static com.cryptomorin.xseries.XEnchantment.FROST_WALKER; -import static com.cryptomorin.xseries.XEnchantment.INFINITY; -import static com.cryptomorin.xseries.XEnchantment.LOYALTY; -import static com.cryptomorin.xseries.XEnchantment.MENDING; -import static com.cryptomorin.xseries.XEnchantment.MULTISHOT; -import static com.cryptomorin.xseries.XEnchantment.PIERCING; -import static com.cryptomorin.xseries.XEnchantment.PROJECTILE_PROTECTION; -import static com.cryptomorin.xseries.XEnchantment.PROTECTION; -import static com.cryptomorin.xseries.XEnchantment.RIPTIDE; -import static com.cryptomorin.xseries.XEnchantment.SHARPNESS; -import static com.cryptomorin.xseries.XEnchantment.SILK_TOUCH; -import static com.cryptomorin.xseries.XEnchantment.SMITE; -import static com.cryptomorin.xseries.XEnchantment.VANISHING_CURSE; - public class IncompatibleEnchants extends IllegalItemModule { private final Set whitelistedTypes; @@ -45,20 +27,20 @@ public class IncompatibleEnchants extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public IncompatibleEnchants() { - super("illegals.enchantments.incompatible-enchants", AEFPermission.BYPASS_ILLEGAL_ENCHANT_INCOMPATIBLE); - this.damageEnchants = new Enchantment[]{SHARPNESS.getEnchant(), SMITE.getEnchant(), BANE_OF_ARTHROPODS.getEnchant()}; - this.protectionEnchants = new Enchantment[]{PROTECTION.getEnchant(), BLAST_PROTECTION.getEnchant(), - FIRE_PROTECTION.getEnchant(), PROJECTILE_PROTECTION.getEnchant()}; - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.enchantments.incompatible-enchants", false, AEFPermission.BYPASS_ILLEGAL_ENCHANT_INCOMPATIBLE, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_ENCHANT_INCOMPATIBLE.node() + "\n" + "Reverts or prevents usage of ItemStacks with Enchantments that\n" + "cannot coexist in vanilla survival minecraft.\n" + "Examples: A bow with mending and infinity or armor with every\n" + "protection enchantment."); + this.damageEnchants = new Enchantment[]{XEnchantment.SHARPNESS.get(), XEnchantment.SMITE.get(), XEnchantment.BANE_OF_ARTHROPODS.get()}; + this.protectionEnchants = new Enchantment[]{XEnchantment.PROTECTION.get(), XEnchantment.BLAST_PROTECTION.get(), + XEnchantment.FIRE_PROTECTION.get(), XEnchantment.PROJECTILE_PROTECTION.get()}; this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", true); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", Collections.singletonList("BOW")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + Collections.singletonList(XMaterial.BOW.get().name())) .stream() .map(configuredType -> { try { @@ -79,7 +61,7 @@ public boolean shouldEnable() { @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -87,18 +69,18 @@ public boolean shouldEnable() { final Set enchantments = itemStack.getEnchantments().keySet(); if (!enchantments.isEmpty()) { - if (enchantments.contains(SILK_TOUCH.getEnchant()) && enchantments.contains(FORTUNE.getEnchant())) + if (enchantments.contains(XEnchantment.SILK_TOUCH.get()) && enchantments.contains(XEnchantment.FORTUNE.get())) return ItemLegality.ILLEGAL; - if (enchantments.contains(DEPTH_STRIDER.getEnchant()) && enchantments.contains(FROST_WALKER.getEnchant())) + if (enchantments.contains(XEnchantment.DEPTH_STRIDER.get()) && enchantments.contains(XEnchantment.FROST_WALKER.get())) return ItemLegality.ILLEGAL; - if (enchantments.contains(INFINITY.getEnchant()) && enchantments.contains(MENDING.getEnchant())) + if (enchantments.contains(XEnchantment.INFINITY.get()) && enchantments.contains(XEnchantment.MENDING.get())) return ItemLegality.ILLEGAL; - if (enchantments.contains(BINDING_CURSE.getEnchant()) && enchantments.contains(VANISHING_CURSE.getEnchant())) + if (enchantments.contains(XEnchantment.BINDING_CURSE.get()) && enchantments.contains(XEnchantment.VANISHING_CURSE.get())) return ItemLegality.ILLEGAL; - if (enchantments.contains(RIPTIDE.getEnchant()) - && (enchantments.contains(LOYALTY.getEnchant()) || enchantments.contains(CHANNELING.getEnchant()))) + if (enchantments.contains(XEnchantment.RIPTIDE.get()) + && (enchantments.contains(XEnchantment.LOYALTY.get()) || enchantments.contains(XEnchantment.CHANNELING.get()))) return ItemLegality.ILLEGAL; - if (enchantments.contains(MULTISHOT.getEnchant()) && enchantments.contains(PIERCING.getEnchant())) + if (enchantments.contains(XEnchantment.MULTISHOT.get()) && enchantments.contains(XEnchantment.PIERCING.get())) return ItemLegality.ILLEGAL; int dmgEnchCount = 0; @@ -133,7 +115,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { if (legality == ItemLegality.LEGAL) return; - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality == ItemLegality.CONTAINS_ILLEGAL) { itemStack.setAmount(0); @@ -142,43 +124,43 @@ public void handleItem(ItemStack itemStack, ItemLegality legality) { final Set enchantments = itemStack.getEnchantments().keySet(); - if (enchantments.contains(SILK_TOUCH.getEnchant()) && enchantments.contains(FORTUNE.getEnchant())) - itemStack.removeEnchantment(FORTUNE.getEnchant()); - if (enchantments.contains(DEPTH_STRIDER.getEnchant()) && enchantments.contains(FROST_WALKER.getEnchant())) - itemStack.removeEnchantment(FROST_WALKER.getEnchant()); - if (enchantments.contains(INFINITY.getEnchant()) && enchantments.contains(MENDING.getEnchant())) - itemStack.removeEnchantment(INFINITY.getEnchant()); - if (enchantments.contains(BINDING_CURSE.getEnchant()) && enchantments.contains(VANISHING_CURSE.getEnchant())) - itemStack.removeEnchantment(BINDING_CURSE.getEnchant()); - if (enchantments.contains(MULTISHOT.getEnchant()) && enchantments.contains(PIERCING.getEnchant())) - itemStack.removeEnchantment(MULTISHOT.getEnchant()); - if (enchantments.contains(RIPTIDE.getEnchant()) && (enchantments.contains(LOYALTY.getEnchant()) || enchantments.contains(CHANNELING.getEnchant()))) - itemStack.removeEnchantment(RIPTIDE.getEnchant()); - - if (enchantments.contains(SHARPNESS.getEnchant())) { // Prefer keeping sharpness enchantment if present + if (enchantments.contains(XEnchantment.SILK_TOUCH.get()) && enchantments.contains(XEnchantment.FORTUNE.get())) + itemStack.removeEnchantment(XEnchantment.FORTUNE.get()); + if (enchantments.contains(XEnchantment.DEPTH_STRIDER.get()) && enchantments.contains(XEnchantment.FROST_WALKER.get())) + itemStack.removeEnchantment(XEnchantment.FROST_WALKER.get()); + if (enchantments.contains(XEnchantment.INFINITY.get()) && enchantments.contains(XEnchantment.MENDING.get())) + itemStack.removeEnchantment(XEnchantment.INFINITY.get()); + if (enchantments.contains(XEnchantment.BINDING_CURSE.get()) && enchantments.contains(XEnchantment.VANISHING_CURSE.get())) + itemStack.removeEnchantment(XEnchantment.BINDING_CURSE.get()); + if (enchantments.contains(XEnchantment.MULTISHOT.get()) && enchantments.contains(XEnchantment.PIERCING.get())) + itemStack.removeEnchantment(XEnchantment.MULTISHOT.get()); + if (enchantments.contains(XEnchantment.RIPTIDE.get()) && (enchantments.contains(XEnchantment.LOYALTY.get()) || enchantments.contains(XEnchantment.CHANNELING.get()))) + itemStack.removeEnchantment(XEnchantment.RIPTIDE.get()); + + if (enchantments.contains(XEnchantment.SHARPNESS.get())) { // Prefer keeping sharpness enchantment if present for (Enchantment dmgEnchant : damageEnchants) { - if (dmgEnchant != SHARPNESS.getEnchant()) { + if (dmgEnchant != XEnchantment.SHARPNESS.get()) { itemStack.removeEnchantment(dmgEnchant); } } - } else if (enchantments.contains(BANE_OF_ARTHROPODS.getEnchant()) && enchantments.contains(SMITE.getEnchant())) { - itemStack.removeEnchantment(BANE_OF_ARTHROPODS.getEnchant()); + } else if (enchantments.contains(XEnchantment.BANE_OF_ARTHROPODS.get()) && enchantments.contains(XEnchantment.SMITE.get())) { + itemStack.removeEnchantment(XEnchantment.BANE_OF_ARTHROPODS.get()); } - if (enchantments.contains(PROTECTION.getEnchant())) { // Prefer keeping protection enchantment if present + if (enchantments.contains(XEnchantment.PROTECTION.get())) { // Prefer keeping protection enchantment if present for (Enchantment protEnchant : protectionEnchants) { - if (protEnchant != PROTECTION.getEnchant()) { + if (protEnchant != XEnchantment.PROTECTION.get()) { itemStack.removeEnchantment(protEnchant); } } - } else if (enchantments.contains(BLAST_PROTECTION.getEnchant())) { // If protection isn't present, prefer blast protection + } else if (enchantments.contains(XEnchantment.BLAST_PROTECTION.get())) { // If protection isn't present, prefer blast protection for (Enchantment protEnchant : protectionEnchants) { - if (protEnchant != BLAST_PROTECTION.getEnchant()) { + if (protEnchant != XEnchantment.BLAST_PROTECTION.get()) { itemStack.removeEnchantment(protEnchant); } } - } else if (enchantments.contains(PROJECTILE_PROTECTION.getEnchant()) && enchantments.contains(FIRE_PROTECTION.getEnchant())) { - itemStack.removeEnchantment(FIRE_PROTECTION.getEnchant()); // If protection and blast protection is not present, prefer projectile protection + } else if (enchantments.contains(XEnchantment.PROJECTILE_PROTECTION.get()) && enchantments.contains(XEnchantment.FIRE_PROTECTION.get())) { + itemStack.removeEnchantment(XEnchantment.FIRE_PROTECTION.get()); // If protection and blast protection is not present, prefer projectile protection } } } \ No newline at end of file diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CommandItems.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CommandItems.java index c99c3d724..0b3006b6f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CommandItems.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CommandItems.java @@ -1,7 +1,7 @@ package me.xginko.aef.modules.illegals.items.nbt; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; @@ -14,20 +14,14 @@ public class CommandItems extends IllegalItemModule { private final boolean checkStored; public CommandItems() { - super("illegals.nbt.command-items", AEFPermission.BYPASS_ILLEGAL_NBT_COMMAND_ITEM); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.nbt.command-items", false, AEFPermission.BYPASS_ILLEGAL_NBT_COMMAND_ITEM, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_NBT_COMMAND_ITEM.node() + "\n" + "Deletes items with commands in their NBT data that run as operator.\n" + "These can only be created by players with creative access.\n" + "Most common items are books, since it allows storing multiple commands."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || itemStack.getType().isAir()) { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CustomNBTFilter.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CustomNBTFilter.java index ae0369127..23c50e9e2 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CustomNBTFilter.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CustomNBTFilter.java @@ -1,8 +1,9 @@ package me.xginko.aef.modules.illegals.items.nbt; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; @@ -24,16 +25,16 @@ public class CustomNBTFilter extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public CustomNBTFilter() { - super("illegals.nbt.ban-custom-tags", AEFPermission.BYPASS_ILLEGAL_NBT_CUSTOM); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Deletes items that have one or more of the configured tags."); + super("illegals.nbt.ban-custom-tags", false, AEFPermission.BYPASS_ILLEGAL_NBT_CUSTOM, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_NBT_CUSTOM.node() + "\n" + + "Deletes items that have one or more of the configured tags."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.illegalTags = new HashSet<>(config.getList(configPath + ".tags", List.of("dmg"), "The exact, case sensitive value of the nbt tag.")); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", false); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", List.of("GOLDEN_APPLE")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + List.of(XMaterial.GOLDEN_APPLE.get().name())) .stream() .map(configuredType -> { try { @@ -47,11 +48,6 @@ public CustomNBTFilter() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || itemStack.getType().isAir()) { @@ -76,7 +72,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/NBTFilledStorageItem.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/NBTFilledStorageItem.java index 2f8fc47f6..7a45b4c5f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/NBTFilledStorageItem.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/items/nbt/NBTFilledStorageItem.java @@ -2,9 +2,9 @@ import com.destroystokyo.paper.MaterialTags; import de.tr7zw.changeme.nbtapi.NBT; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; @@ -25,14 +25,13 @@ public class NBTFilledStorageItem extends IllegalItemModule { private final boolean checkStored; public NBTFilledStorageItem() { - super("illegals.nbt.impossibly-stored-items", AEFPermission.BYPASS_ILLEGAL_NBT_STOREDITEMS); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Prevents usage of or deletes storage items that have been pre-filled\n" + - "with items using NBT tags. These can only be created by players with\n" + - "creative access.\n" + - "Most commonly dispensers, droppers and chests containing kit shulkers\n" + - "are created but there are more combinations possible."); + super("illegals.nbt.impossibly-stored-items", false, AEFPermission.BYPASS_ILLEGAL_NBT_STOREDITEMS, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_NBT_STOREDITEMS.node() + "\n" + + "Prevents usage of or deletes storage items that have been pre-filled\n" + + "with items using NBT tags. These can only be created by players with\n" + + "creative access.\n" + + "Most commonly dispensers, droppers and chests containing kit shulkers\n" + + "are created but there are more combinations possible."); this.stored_items_tag = config.getString(configPath + ".tag", "BlockEntityTag", "The exact name of the nbt tag that signals items are stored inside."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); @@ -51,11 +50,6 @@ public NBTFilledStorageItem() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || itemStack.getType().isAir()) { @@ -75,7 +69,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/PeriodicallyRemoveIllegalBlocks.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/PeriodicallyRemoveIllegalBlocks.java index 9555a7b25..31be9fd86 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/PeriodicallyRemoveIllegalBlocks.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/PeriodicallyRemoveIllegalBlocks.java @@ -4,6 +4,7 @@ import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.World; @@ -16,22 +17,36 @@ import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.stream.Stream; public class PeriodicallyRemoveIllegalBlocks extends AEFModule implements Consumer { - private ScheduledTask scheduledTask; private final Set blocksToRemove; private final Set exemptedWorlds; private final long checkPeriod; private final double pauseTPS; private final boolean checkShouldPauseOnLowTPS; + private ScheduledTask scheduledTask; + public PeriodicallyRemoveIllegalBlocks() { - super("illegals.remove-placed-blocks.periodically"); - this.blocksToRemove = config.getList(configPath + ".blocks-to-remove", - List.of("PLAYER_HEAD", "CHAIN_COMMAND_BLOCK", "COMMAND_BLOCK", "COMMAND_BLOCK_MINECART", - "REPEATING_COMMAND_BLOCK", "BEDROCK", "BARRIER"), - "Enter PLAYER_HEAD here if you want to remove placed playerheads.") + super("illegals.remove-placed-blocks.periodically", false); + List defaults = Stream.of( + XMaterial.PLAYER_HEAD, + XMaterial.PLAYER_WALL_HEAD, + XMaterial.COMMAND_BLOCK, + XMaterial.CHAIN_COMMAND_BLOCK, + XMaterial.REPEATING_COMMAND_BLOCK, + XMaterial.BEDROCK, + XMaterial.BARRIER, + XMaterial.STRUCTURE_BLOCK, + XMaterial.STRUCTURE_VOID, + XMaterial.LIGHT) + .filter(XMaterial::isSupported) + .map(XMaterial::get) + .map(Enum::name) + .toList(); + this.blocksToRemove = config.getList(configPath + ".blocks-to-remove", defaults) .stream() .map(configuredType -> { try { @@ -52,18 +67,16 @@ public PeriodicallyRemoveIllegalBlocks() { @Override public void enable() { - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @Override @@ -76,8 +89,10 @@ public void accept(ScheduledTask task) { final boolean inNether = world.getEnvironment() == World.Environment.NETHER; for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { - if (checkShouldPauseOnLowTPS && (AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS)) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; if (!chunk.isEntitiesLoaded()) return; for (int x = 0; x < 16; x++) { @@ -87,20 +102,20 @@ public void accept(ScheduledTask task) { if (!blocksToRemove.contains(block.getType())) continue; // If is bedrock, make sure not to delete naturally generated - if (block.getType() == XMaterial.BEDROCK.parseMaterial()) { + if (block.getType() == XMaterial.BEDROCK.get()) { if (y > minY + 4) { // offset to not delete natural bedrock floor if (inNether) { // offset to not delete bedrock ceiling if (y < config.nether_ceiling_max_y - 5) - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } else { - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } continue; } - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveIllegalBlocksOnChunkload.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveIllegalBlocksOnChunkload.java index 5fcbee944..ecb0502a4 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveIllegalBlocksOnChunkload.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveIllegalBlocksOnChunkload.java @@ -3,7 +3,7 @@ import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; -import org.bukkit.Chunk; +import me.xginko.aef.utils.ChunkUtil; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -19,6 +19,7 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; public class RemoveIllegalBlocksOnChunkload extends AEFModule implements Listener { @@ -28,12 +29,24 @@ public class RemoveIllegalBlocksOnChunkload extends AEFModule implements Listene private final double pauseTPS; public RemoveIllegalBlocksOnChunkload() { - super("illegals.remove-placed-blocks.on-chunkload"); - config.addComment(configPath + ".enable", + super("illegals.remove-placed-blocks.on-chunkload", false, "Remove illegally placed blocks on chunkload."); - this.blocksToRemove = config.getList(configPath + ".blocks-to-remove", - List.of("PLAYER_HEAD", "CHAIN_COMMAND_BLOCK", "COMMAND_BLOCK", "COMMAND_BLOCK_MINECART", - "REPEATING_COMMAND_BLOCK", "BEDROCK", "BARRIER"), + List defaults = Stream.of( + XMaterial.PLAYER_HEAD, + XMaterial.PLAYER_WALL_HEAD, + XMaterial.COMMAND_BLOCK, + XMaterial.CHAIN_COMMAND_BLOCK, + XMaterial.REPEATING_COMMAND_BLOCK, + XMaterial.BEDROCK, + XMaterial.BARRIER, + XMaterial.STRUCTURE_BLOCK, + XMaterial.STRUCTURE_VOID, + XMaterial.LIGHT) + .filter(XMaterial::isSupported) + .map(XMaterial::get) + .map(Enum::name) + .toList(); + this.blocksToRemove = config.getList(configPath + ".blocks-to-remove", defaults, "Enter PLAYER_HEAD here if you want to remove placed playerheads.") .stream() .map(configuredType -> { @@ -57,11 +70,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -70,37 +78,35 @@ public void disable() { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { if (event.isNewChunk()) return; - if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; - - Chunk chunk = event.getChunk(); - World world = chunk.getWorld(); - if (exemptedWorlds.contains(world.getName())) return; + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; + if (exemptedWorlds.contains(event.getWorld().getName())) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; - final int minY = world.getMinHeight(); - final int maxY = world.getMaxHeight(); - final boolean inNether = world.getEnvironment() == World.Environment.NETHER; + final int minY = event.getWorld().getMinHeight(); + final int maxY = event.getWorld().getMaxHeight(); + final boolean inNether = event.getWorld().getEnvironment() == World.Environment.NETHER; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = minY; y < maxY; y++) { - Block block = chunk.getBlock(x, y, z); + Block block = event.getChunk().getBlock(x, y, z); if (!blocksToRemove.contains(block.getType())) continue; // If is bedrock, make sure not to delete naturally generated - if (block.getType() == XMaterial.BEDROCK.parseMaterial()) { + if (block.getType() == XMaterial.BEDROCK.get()) { if (y > minY + 4) { // offset to not delete natural bedrock floor if (inNether) { // offset to not delete bedrock ceiling if (y < config.nether_ceiling_max_y - 5) - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } else { - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } continue; } - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveUnnaturalSpawners.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveUnnaturalSpawners.java index 7add22e96..b5e3f03e0 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveUnnaturalSpawners.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveUnnaturalSpawners.java @@ -5,8 +5,7 @@ import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; -import org.bukkit.Chunk; -import org.bukkit.World; +import me.xginko.aef.utils.ChunkUtil; import org.bukkit.block.Block; import org.bukkit.block.CreatureSpawner; import org.bukkit.entity.EntityType; @@ -23,36 +22,52 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; public class RemoveUnnaturalSpawners extends AEFModule implements Listener { - private final Map> naturalSpawners = new HashMap<>(); + private final Map> naturalSpawners; private final boolean checkShouldPauseOnLowTPS; private final double pauseTPS; public RemoveUnnaturalSpawners() { - super("illegals.remove-unnatural-spawners-on-chunkload"); + super("illegals.remove-unnatural-spawners-on-chunkload", false); this.checkShouldPauseOnLowTPS = config.getBoolean(configPath + ".pause-on-low-TPS", false); this.pauseTPS = config.getDouble(configPath + ".pause-TPS", 14.0); - Map defaults = new HashMap<>(); - defaults.put("world", List.of( - XEntityType.SKELETON.get().name(), - XEntityType.ZOMBIE.get().name(), - XEntityType.SILVERFISH.get().name(), - XEntityType.SPIDER.get().name(), - XEntityType.CAVE_SPIDER.get().name())); - defaults.put("world_nether", List.of( - XEntityType.BLAZE.get().name(), - XEntityType.MAGMA_CUBE.get().name())); - defaults.put("world_the_end", List.of( - XEntityType.SKELETON.get().name(), - XEntityType.SPIDER.get().name())); + Map defaults = new HashMap<>(3); + defaults.put("world", Stream.of( + XEntityType.SKELETON, + XEntityType.ZOMBIE, + XEntityType.SILVERFISH, + XEntityType.SPIDER, + XEntityType.CAVE_SPIDER, + XEntityType.BREEZE) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList())); + defaults.put("world_nether", Stream.of( + XEntityType.BLAZE, + XEntityType.MAGMA_CUBE) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList())); + defaults.put("world_the_end", Stream.of( + XEntityType.SKELETON, + XEntityType.SPIDER) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList())); ConfigSection section = config.getConfigSection(configPath + ".natural-spawner-types-per-world", defaults, "You can add or remove as much world names here as you want."); - for (String configuredWorlds : section.getKeys(false)) { - naturalSpawners.put(configuredWorlds, section.getList(configuredWorlds) + List worlds = section.getKeys(false); + this.naturalSpawners = new HashMap<>(worlds.size()); + for (String world : worlds) { + naturalSpawners.put(world, section.getList(world) .stream() .map(String::valueOf) .map(configuredType -> { @@ -74,11 +89,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -86,23 +96,22 @@ public void disable() { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { - if (event.isNewChunk() || checkShouldPauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; - - Chunk chunk = event.getChunk(); - World world = chunk.getWorld(); - if (!naturalSpawners.containsKey(world.getName())) return; + if (event.isNewChunk()) return; + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; + if (!naturalSpawners.containsKey(event.getWorld().getName())) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; - final int minY = world.getMinHeight(); - final int maxY = world.getMaxHeight(); + final int minY = event.getWorld().getMinHeight(); + final int maxY = event.getWorld().getMaxHeight(); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = minY; y < maxY; y++) { - Block block = chunk.getBlock(x, y, z); - if (block.getType() == XMaterial.SPAWNER.parseMaterial() - && !naturalSpawners.get(world.getName()).contains(((CreatureSpawner) block.getState()).getSpawnedType()) + Block block = event.getChunk().getBlock(x, y, z); + if (block.getType() == XMaterial.SPAWNER.get() + && !naturalSpawners.get(event.getWorld().getName()).contains(((CreatureSpawner) block.getState()).getSpawnedType()) ) { - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/DisableCustomEntities.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/DisableCustomEntities.java new file mode 100755 index 000000000..f78826e70 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/DisableCustomEntities.java @@ -0,0 +1,71 @@ +package me.xginko.aef.modules.lagpreventions; + +import com.cryptomorin.xseries.XEntityType; +import me.xginko.aef.modules.AEFModule; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntitySpawnEvent; + +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class DisableCustomEntities extends AEFModule implements Listener { + + private final Set disabledEntities; + + public DisableCustomEntities() { + super("lag-preventions.disable-entity-spawns", false,""" + Prevent certain entity types from spawning to combat lag. + Fish types are enabled by default on newer versions since they + can cause a ton of lag."""); + + List defaults = Stream.of( + XEntityType.COD, + XEntityType.SALMON, + XEntityType.PUFFERFISH, + XEntityType.TROPICAL_FISH, + XEntityType.BAT, + XEntityType.PHANTOM) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .toList(); + + this.disabledEntities = config.getList(configPath + ".types", defaults) + .stream() + .map(configuredType -> { + try { + return EntityType.valueOf(configuredType); + } catch (IllegalArgumentException exception) { + notRecognized(EntityType.class, configuredType); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityType.class))); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntitySpawn(EntitySpawnEvent event) { + if (disabledEntities.contains(event.getEntityType())) { + event.setCancelled(true); + } + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/FloodingMachines.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/FloodingMachines.java index 6c87044d2..ab8f7e3dd 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/FloodingMachines.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/FloodingMachines.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.lagpreventions; +import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.BlockUtil; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -15,8 +15,7 @@ public class FloodingMachines extends AEFModule implements Listener { private final boolean remove; public FloodingMachines() { - super("lag-preventions.prevent-flooding-machines"); - config.addComment(configPath + ".enable", """ + super("lag-preventions.prevent-flooding-machines", false, """ Will prevent pistons from pushing waterlogged blocks.\s Stops players from using waterlogged blocks and piston flying\s machines to generate large walls of water that generate lag\s @@ -34,16 +33,11 @@ public void disable() { HandlerList.unregisterAll(this); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPistonExtend(BlockPistonExtendEvent event) { for (Block block : event.getBlocks()) { if (BlockUtil.isWaterlogged(block.getState())) { - if (remove) block.setType(Material.AIR); + if (remove) block.setType(XMaterial.AIR.get()); event.setCancelled(true); return; } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/KeepStashLoaded.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/KeepStashLoaded.java index 8c2a7ad5b..97aa9478a 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/KeepStashLoaded.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/KeepStashLoaded.java @@ -3,6 +3,7 @@ import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.MaterialUtil; import me.xginko.aef.utils.models.ChunkUID; import org.bukkit.Chunk; @@ -17,6 +18,7 @@ import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -31,16 +33,16 @@ */ public class KeepStashLoaded extends AEFModule implements Consumer, Listener { - private final Map forceLoadedChunks; - private final Map worldsAndTheirRadiuses = new HashMap<>(); + private final Map worldsAndTheirRadiuses; private final Set storageTypes; - private final long minInhabitedTime, keepLoadedMillis; + private final long minInhabitedTime, keepLoadedMillis, checkDelayTicks; private final int stashCount; private final boolean logIsEnabled, onlyTileEntities; + private Map forceLoadedChunks; + public KeepStashLoaded() { - super("lag-preventions.keep-stash-chunks-loaded"); - this.forceLoadedChunks = new ConcurrentHashMap<>(); + super("lag-preventions.keep-stash-chunks-loaded", false); config.addComment(configPath + ".enable", """ Idea by 3b3t admin kumori (Soft1k)\s Improves lag generated by large stash chunks constantly loading and\s @@ -50,6 +52,9 @@ public KeepStashLoaded() { this.stashCount = config.getInt(configPath + ".container-block-threshold", 50, """ How many container blocks have to be in a chunk for it to be seen\s as a stash chunk to keep force loaded."""); + this.checkDelayTicks = config.getInt(configPath + ".check-delay-ticks", 200, """ + Ticks to wait after a chunk is loaded before it will be checked.\s + Reduces lag by fast travelling players."""); this.minInhabitedTime = config.getInt(configPath + ".min-chunk-inhabited-time-ticks", 1000, """ The minimum time in ticks a chunk has to have been inhabited to be checked."""); this.keepLoadedMillis = TimeUnit.MINUTES.toMillis(config.getInt(configPath + ".keep-loaded-minutes", 120, """ @@ -80,7 +85,9 @@ public KeepStashLoaded() { ConfigSection section = config.getConfigSection(configPath + ".worlds", defaults, "Radiuses around spawn in chunks (not blocks) that should not be checked.\n" + "Worlds not on this list are exempt from all checking."); - for (String world : section.getKeys(false)) { + List worlds = section.getKeys(false); + this.worldsAndTheirRadiuses = new HashMap<>(worlds.size()); + for (String world : worlds) { try { int radius = Integer.parseInt(section.getString(world)); this.worldsAndTheirRadiuses.put(world, NumberConversions.square(radius)); @@ -92,6 +99,7 @@ public KeepStashLoaded() { @Override public void enable() { + forceLoadedChunks = new ConcurrentHashMap<>(); plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getAsyncScheduler().runAtFixedRate(plugin, this, 1L, 1L, TimeUnit.MINUTES); } @@ -99,20 +107,19 @@ public void enable() { @Override public void disable() { HandlerList.unregisterAll(this); - for (Map.Entry entry : forceLoadedChunks.entrySet()) { - entry.getKey().getChunkAsync(false).thenAccept(chunk -> { - if (chunk != null) - plugin.getServer().getGlobalRegionScheduler().execute(plugin, () -> chunk.setForceLoaded(false)); - forceLoadedChunks.remove(entry.getKey()); - }); + if (forceLoadedChunks != null) { + for (Map.Entry entry : forceLoadedChunks.entrySet()) { + entry.getKey().getChunkAsync(false).thenAccept(chunk -> { + if (chunk != null) { + ChunkUtil.setForceLoaded(chunk, false); + } + }); + } + forceLoadedChunks.clear(); + forceLoadedChunks = null; } } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void accept(ScheduledTask task) { for (Map.Entry entry : forceLoadedChunks.entrySet()) { @@ -141,6 +148,7 @@ public void accept(ScheduledTask task) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { if (event.isNewChunk()) return; + final String world = event.getWorld().getName(); if (!worldsAndTheirRadiuses.containsKey(world)) return; @@ -149,31 +157,28 @@ private void onChunkLoad(ChunkLoadEvent event) { if (chunk.getInhabitedTime() < minInhabitedTime) return; if (NumberConversions.square(chunk.getX()) + NumberConversions.square(chunk.getZ()) < worldsAndTheirRadiuses.get(world)) return; - if (isStashChunk(chunk)) { - forceLoadedChunks.computeIfAbsent(ChunkUID.of(chunk), chunkUID -> { - plugin.getServer().getGlobalRegionScheduler().execute(plugin, () -> { - chunk.setForceLoaded(true); - if (logIsEnabled) - info("Set chunk " + chunkUID + " to force loaded."); - }); - return System.currentTimeMillis() + keepLoadedMillis; - }); - } - } - - private boolean isStashChunk(Chunk chunk) { - int count = 0; - - if (onlyTileEntities) { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (storageTypes.contains(tileEntity.getType())) { - count++; - if (count > stashCount) { - return true; + plugin.getServer().getRegionScheduler().runDelayed(plugin, chunk.getWorld(), chunk.getX(), chunk.getZ(), delayedCheck -> { + if (!chunk.isLoaded()) return; + + int count = 0; + + if (onlyTileEntities) { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (storageTypes.contains(tileEntity.getType())) { + count++; + if (count > stashCount) { + chunk.setForceLoaded(true); + forceLoadedChunks.computeIfAbsent(ChunkUID.of(chunk), chunkUID -> { + if (logIsEnabled) info("Set chunk " + chunkUID + " to force loaded."); + return System.currentTimeMillis() + keepLoadedMillis; + }); + return; + } } } + return; } - } else { + final int minY = chunk.getWorld().getMinHeight(); final int maxY = chunk.getWorld().getMaxHeight(); @@ -183,14 +188,17 @@ private boolean isStashChunk(Chunk chunk) { if (storageTypes.contains(chunk.getBlock(x, y, z).getType())) { count++; if (count > stashCount) { - return true; + chunk.setForceLoaded(true); + forceLoadedChunks.computeIfAbsent(ChunkUID.of(chunk), chunkUID -> { + if (logIsEnabled) info("Set chunk " + chunkUID + " to force loaded."); + return System.currentTimeMillis() + keepLoadedMillis; + }); + return; } } } } } - } - - return false; + }, checkDelayTicks); } -} +} \ No newline at end of file diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/LeverSpam.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/LeverSpam.java index eafb5769a..f7ff797e3 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/LeverSpam.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/LeverSpam.java @@ -19,46 +19,50 @@ public class LeverSpam extends AEFModule implements Listener { - private final Cache leverLocationCooldowns; - private final Cache playersUsingLeversCooldowns; + private final long cacheTimeMillis; private final int leverUsageLimit; private final boolean shouldKickPlayer, sendActionBar; + private Cache leverLocationCooldowns; + private Cache playersUsingLeversCooldowns; + public LeverSpam() { - super("lag-preventions.prevent-lever-spam"); - config.addComment(configPath + ".enable", "Rate Limit levers to prevent a lag exploit."); + super("lag-preventions.prevent-lever-spam", false, + "Rate Limit levers to prevent a lag exploit."); this.sendActionBar = config.getBoolean(configPath + ".show-actionbar", true); this.shouldKickPlayer = config.getBoolean(configPath + ".kick-player", false); this.leverUsageLimit = config.getInt(configPath + ".max-lever-usages-per-time", 15); - final long cacheTimeMillis = config.getInt(configPath + ".lever-time-in-ticks", 40) * 50L; - this.leverLocationCooldowns = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); - this.playersUsingLeversCooldowns = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); + this.cacheTimeMillis = config.getInt(configPath + ".lever-time-in-ticks", 40) * 50L; } @Override public void enable() { + leverLocationCooldowns = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); + playersUsingLeversCooldowns = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (leverLocationCooldowns != null) { + leverLocationCooldowns.invalidateAll(); + leverLocationCooldowns.cleanUp(); + leverLocationCooldowns = null; + } + if (playersUsingLeversCooldowns != null) { + playersUsingLeversCooldowns.invalidateAll(); + playersUsingLeversCooldowns.cleanUp(); + playersUsingLeversCooldowns = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onInteract(PlayerInteractEvent event) { if (!event.getAction().isRightClick()) return; - Block clicked = event.getClickedBlock(); - if (clicked.getType() != XMaterial.LEVER.parseMaterial()) return; - - final Player player = event.getPlayer(); + if (event.getClickedBlock().getType() != XMaterial.LEVER.get()) return; - final Location leverLoc = clicked.getLocation(); + final Location leverLoc = event.getClickedBlock().getLocation(); Integer activationCount = leverLocationCooldowns.getIfPresent(leverLoc); if (activationCount == null) activationCount = 0; @@ -68,30 +72,29 @@ private void onInteract(PlayerInteractEvent event) { if (activationCount > leverUsageLimit) { event.setCancelled(true); if (shouldKickPlayer) { - player.kick(AnarchyExploitFixes.getLang(player.locale()).lagpreventions_stopSpammingLevers); + event.getPlayer().kick(AnarchyExploitFixes.getLang(event.getPlayer().locale()).lagpreventions_stopSpammingLevers); return; } if (sendActionBar) { - player.sendActionBar(AnarchyExploitFixes.getLang(player.locale()).lagpreventions_stopSpammingLevers); + event.getPlayer().sendActionBar(AnarchyExploitFixes.getLang(event.getPlayer().locale()).lagpreventions_stopSpammingLevers); } return; } - final UUID playerUniqueId = player.getUniqueId(); - Integer leverFlickCount = playersUsingLeversCooldowns.getIfPresent(playerUniqueId); + Integer leverFlickCount = playersUsingLeversCooldowns.getIfPresent(event.getPlayer().getUniqueId()); if (leverFlickCount == null) leverFlickCount = 0; leverFlickCount++; - playersUsingLeversCooldowns.put(playerUniqueId, leverFlickCount); + playersUsingLeversCooldowns.put(event.getPlayer().getUniqueId(), leverFlickCount); if (leverFlickCount > leverUsageLimit) { event.setCancelled(true); if (shouldKickPlayer) { - player.kick(AnarchyExploitFixes.getLang(player.locale()).lagpreventions_stopSpammingLevers); + event.getPlayer().kick(AnarchyExploitFixes.getLang(event.getPlayer().locale()).lagpreventions_stopSpammingLevers); return; } if (sendActionBar) { - player.sendActionBar(AnarchyExploitFixes.getLang(player.locale()).lagpreventions_stopSpammingLevers); + event.getPlayer().sendActionBar(AnarchyExploitFixes.getLang(event.getPlayer().locale()).lagpreventions_stopSpammingLevers); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/NoShulkerDrops.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/NoShulkerDrops.java index 5f2633ef6..8fdbc4c0a 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/NoShulkerDrops.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/NoShulkerDrops.java @@ -13,8 +13,7 @@ public class NoShulkerDrops extends AEFModule implements Listener { public NoShulkerDrops() { - super("lag-preventions.anti-shulker-drops"); - config.addComment(configPath + ".enable", """ + super("lag-preventions.anti-shulker-drops", false, """ Disables shulkers dropping stored items when blown up.\s This helps fix client- and serverside lag when done often and fast."""); } @@ -29,20 +28,18 @@ public void disable() { HandlerList.unregisterAll(this); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityDamage(EntityDamageEvent event) { if (event.getEntityType() != XEntityType.ITEM.get()) return; - Item item = (Item) event.getEntity(); - if (!MaterialTags.SHULKER_BOXES.isTagged(item.getItemStack())) return; - if (event.getFinalDamage() >= item.getHealth()) { - event.setCancelled(true); // Cancel damage so the drop logic doesn't happen - item.remove(); // remove entity + if (event.getCause() == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION || event.getCause() == EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) { + Item item = (Item) event.getEntity(); + if (!MaterialTags.SHULKER_BOXES.isTagged(item.getItemStack())) return; + + if (event.getFinalDamage() >= item.getHealth()) { + event.setCancelled(true); // Cancel damage so the drop logic doesn't happen + item.remove(); // remove entity + } } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/StashExplosions.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/StashExplosions.java index 1144b62b6..2904cbfc8 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/StashExplosions.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/StashExplosions.java @@ -1,6 +1,7 @@ package me.xginko.aef.modules.lagpreventions; import com.cryptomorin.xseries.XEntityType; +import com.cryptomorin.xseries.XMaterial; import com.destroystokyo.paper.MaterialTags; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; @@ -26,25 +27,24 @@ public class StashExplosions extends AEFModule implements Listener { - private final Cache containerExplosions; private final Set storageTypes; + private final long waitTimeSeconds; private final int amountAtWhichToTakeAction; private final boolean logIsEnabled; + private Cache containerExplosions; + public StashExplosions() { - super("lag-preventions.disable-item-drops-during-large-stash-explosions"); - config.addComment(configPath + ".enable", """ + super("lag-preventions.disable-item-drops-during-large-stash-explosions", false, """ Explodes containers without dropping items after a certain amount\s of exploded containers per chunk."""); this.logIsEnabled = config.getBoolean(configPath + ".log", false); this.amountAtWhichToTakeAction = config.getInt(configPath + ".min-explosions-before-drops-disable", 6, """ How many container blocks in a chunk can be blown up until items\s no longer drop from them."""); - this.containerExplosions = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds( - Math.max(1, config.getInt(configPath + ".time-in-seconds", 3, """ - The time in seconds to wait after an explosion for another one to happen.\s - If no explosion happens within x seconds after the first one, the count resets to 0.""")) - )).build(); + this.waitTimeSeconds = Math.max(1, config.getInt(configPath + ".time-in-seconds", 3, """ + The time in seconds to wait after an explosion for another one to happen.\s + If no explosion happens within x seconds after the first one, the count resets to 0.""")); this.storageTypes = config.getList(configPath + ".container-types", MaterialUtil.INVENTORY_HOLDERS .stream() .filter(material -> !MaterialTags.SHULKER_BOXES.isTagged(material)) @@ -64,18 +64,18 @@ public StashExplosions() { @Override public void enable() { + containerExplosions = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(waitTimeSeconds)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } @Override public void disable() { HandlerList.unregisterAll(this); - containerExplosions.asMap().clear(); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); + if (containerExplosions != null) { + containerExplosions.invalidateAll(); + containerExplosions.cleanUp(); + containerExplosions = null; + } } private void handleExplosion(Chunk chunk, List affectedBlocks) { @@ -90,7 +90,7 @@ private void handleExplosion(Chunk chunk, List affectedBlocks) { affectedBlocks.removeIf(block -> { if (storageTypes.contains(block.getType())) { - block.setType(Material.AIR); + block.setType(XMaterial.AIR.get()); return true; } return false; @@ -115,7 +115,9 @@ private void onBlockExplode(BlockExplodeEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityExplode(EntityExplodeEvent event) { - if (event.getEntityType().equals(XEntityType.WIND_CHARGE.get())) return; + if (event.getEntityType() == XEntityType.WIND_CHARGE.get()) return; + if (event.getEntityType() == XEntityType.BREEZE_WIND_CHARGE.get()) return; + handleExplosion(event.getEntity().getChunk(), event.blockList()); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/CustomAgeLimits.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/CustomAgeLimits.java index 3ed74dd8d..052c118c7 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/CustomAgeLimits.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/CustomAgeLimits.java @@ -4,6 +4,7 @@ import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.World; @@ -13,7 +14,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.EntitiesLoadEvent; import java.util.EnumMap; import java.util.Map; @@ -22,14 +23,14 @@ public class CustomAgeLimits extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; private final Map entityLimits = new EnumMap<>(EntityType.class); private final long checkPeriod; private final boolean logIsEnabled, forceLoadEntities; + private ScheduledTask scheduledTask; + public CustomAgeLimits() { - super("lag-preventions.entity-age-limits.custom-limits"); - config.addComment(configPath + ".enable", + super("lag-preventions.entity-age-limits.custom-limits", false, "Kill certain entities after a custom amount of ticks lived."); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", false); this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 1200, """ @@ -77,29 +78,27 @@ public void enable() { .runAtFixedRate(plugin, this, 20L, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (scheduledTask != null) + if (scheduledTask != null) { scheduledTask.cancel(); + scheduledTask = null; + } } @Override public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!forceLoadEntities && !chunk.isEntitiesLoaded()) return; for (Entity entity : chunk.getEntities()) { entity.getScheduler().execute(plugin, () -> { - if (entityLimits.containsKey(entity.getType()) - && entity.getTicksLived() >= entityLimits.get(entity.getType())) { + if (entityLimits.containsKey(entity.getType()) && entity.getTicksLived() > entityLimits.get(entity.getType())) { entity.remove(); if (logIsEnabled) info("Removed " + entity.getType().name() + " due to old age."); @@ -112,12 +111,10 @@ public void accept(ScheduledTask task) { } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onChunkLoad(ChunkLoadEvent event) { - if (event.isNewChunk()) return; - - for (Entity entity : event.getChunk().getEntities()) { - if (entityLimits.containsKey(entity.getType()) && entity.getTicksLived() >= entityLimits.get(entity.getType())) { - entity.remove(); + private void onEntitiesLoad(EntitiesLoadEvent event) { + for (Entity entity : event.getEntities()) { + if (entityLimits.containsKey(entity.getType()) && entity.getTicksLived() > entityLimits.get(entity.getType())) { + entity.getScheduler().execute(plugin, entity::remove, null, 1L); if (logIsEnabled) info("Removed " + entity.getType().name() + " due to old age."); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java index 50ee2a82f..02ce86ef8 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java @@ -2,27 +2,33 @@ import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.entity.Entity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.world.ChunkLoadEvent; import java.util.function.Consumer; -public class ProjectileAgeLimit extends AEFModule implements Consumer { +public class ProjectileAgeLimit extends AEFModule implements Consumer, Listener { - private ScheduledTask scheduledTask; private final long check_period_in_ticks; private final int max_alive_time; + private ScheduledTask scheduledTask; + public ProjectileAgeLimit() { - super("lag-preventions.entity-age-limits.projectile-limit"); - config.addComment(configPath + ".enable", - "Patches any lag exploit that abuses spawning a ton of projectile entities\n" + - "(ex. Snowball exploit)." + - "Skips over the following entities: ENDER_PEARL, FISHING_HOOK, WITHER_SKULL\n" + - "and ENDER_SIGNAL. You can configure those separately in the custom entity age\n" + - "limit section."); + super("lag-preventions.entity-age-limits.projectile-limit", false, """ + Patches any lag exploit that abuses spawning a ton of projectile entities + (ex. Snowball exploit). + Skips over the following entities: ENDER_PEARL, FISHING_HOOK, WITHER_SKULL + and ENDER_SIGNAL. You can configure those separately in the custom entity age + limit section."""); this.max_alive_time = config.getInt(configPath + ".max-alive-time-ticks", 300, "(20 ticks = 1 second) Will not touch Ender Pearls"); this.check_period_in_ticks = config.getInt(configPath + ".check-period-seconds", 20, @@ -31,24 +37,26 @@ public ProjectileAgeLimit() { @Override public void enable() { - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() + scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, check_period_in_ticks, check_period_in_ticks); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); + plugin.getServer().getPluginManager().registerEvents(this, plugin); } @Override public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); + HandlerList.unregisterAll(this); + if (scheduledTask != null) { + scheduledTask.cancel(); + scheduledTask = null; + } } @Override public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { for (Entity entity : chunk.getEntities()) { entity.getScheduler().execute(plugin, () -> { @@ -68,4 +76,25 @@ public void accept(ScheduledTask task) { } } } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onChunkLoad(ChunkLoadEvent event) { + if (event.isNewChunk()) return; + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; + + for (Entity entity : event.getChunk().getEntities()) { + entity.getScheduler().execute(plugin, () -> { + if (EntityUtil.isProjectile(entity)) { + switch (entity.getType()) { + case ENDER_PEARL, WITHER_SKULL, FISHING_HOOK, ENDER_SIGNAL -> { + return; + } + } + if (entity.getTicksLived() > max_alive_time) { + entity.remove(); + } + } + }, null, 1L); + } + } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockFormOrGrow.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockFormOrGrow.java index 73d4333f1..0318a47fd 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockFormOrGrow.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockFormOrGrow.java @@ -1,25 +1,29 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XMaterial; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockSpreadEvent; -public class BlockFormOrGrow extends RegionalActivityModule { +import java.util.Map; - private final int limit; +public class BlockFormOrGrow extends RegionalBlockActivityModule { public BlockFormOrGrow() { super( "block-spread", false, + true, + 2000, 1500.0, 6000, 10000, 10.0, - 120.0 - ); - config.addComment(configPath+".enable", """ + 120.0, + Map.of( XMaterial.ICE, 1000, + XMaterial.SNOW, 1000), + """ Limits blocks spreading or forming based on world conditions within a\s configurable radius and timeframe to help reduce lag by cancelling burst\s activity hotspots.\s @@ -31,22 +35,20 @@ public BlockFormOrGrow() { - Obsidian / Cobblestone forming due to contact with water.\s - Concrete forming due to mixing of concrete powder and water.\s - Mushrooms spreading.\s - - Fire spreading."""); - this.limit = config.getInt(configPath + ".block-form-event-limit", 800, - "Maximum number of times a block can form or spread within the configured\n" + - "timeframe before activity will be put on cooldown."); + - Fire spreading.""" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockForm(BlockFormEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockSpread(BlockSpreadEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockPhysics.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockPhysics.java index c328a2d80..dfb82850f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockPhysics.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockPhysics.java @@ -1,24 +1,28 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XMaterial; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPhysicsEvent; -public class BlockPhysics extends RegionalActivityModule { +import java.util.Map; - private final int limit; +public class BlockPhysics extends RegionalBlockActivityModule { public BlockPhysics() { super( "block-physics", + false, true, + 512000, 1500.0, 18000, 20000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ + 120.0, + Map.of( XMaterial.WATER, 256000, + XMaterial.LAVA, 256000), + """ Limits block physics within a configurable radius and timeframe\s to help reduce lag by cancelling burst activity hotspots.\s \s @@ -29,15 +33,13 @@ The event used for this check (BlockPhysicsEvent) is a high frequency event,\s Where possible the event may also only be called for the "root" block of\s physics updates in order to limit event spam.\s Physics updates that cause other blocks to change their state may not result\s - in an event for each of those blocks (usually adjacent)."""); - this.limit = config.getInt(configPath + ".block-physics-event-limit", 256000, - "Maximum number of times a physics check can be performed within the configured\n" + - "timeframe before they will be put on cooldown."); + in an event for each of those blocks (usually adjacent).""" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPhysics(BlockPhysicsEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntitySpawns.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntitySpawns.java index 16b4451e8..ed18ef3c1 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntitySpawns.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntitySpawns.java @@ -1,24 +1,28 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XEntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntitySpawnEvent; -public class EntitySpawns extends RegionalActivityModule { +import java.util.Map; - private final int limit; +public class EntitySpawns extends RegionalEntityActivityModule { public EntitySpawns() { super( "entity-spawn", + false, true, + 6000, 1500.0, 18000, 20000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ + 120.0, + Map.of( XEntityType.WITHER, 50, + XEntityType.WITHER_SKULL, 200), + """ Limits entity spawning activity within a configurable radius and timeframe\s to help reduce lag by cancelling high activity hotspots.\s \s @@ -26,14 +30,13 @@ public EntitySpawns() { \s - A creature gets spawned naturally, by spawner or other reasons.\s - An entity gets spawned naturally, by spawner or other reasons.\s - This does not include tile entities."""); - this.limit = config.getInt(configPath + ".spawn-event-limit", 6000, - "Maximum number of entity spawns within configured timeframe."); + This does not include tile entities.""" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntitySpawn(EntitySpawnEvent event) { - if (shouldCancelActivity(event, event.getLocation(), limit)) { + if (shouldCancelEntityEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntityTargeting.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntityTargeting.java index bd60ab6a0..6de4d5742 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntityTargeting.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntityTargeting.java @@ -3,12 +3,9 @@ import com.cryptomorin.xseries.XEntityType; import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import me.xginko.aef.utils.LocationUtil; -import org.bukkit.Location; -import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.util.NumberConversions; @@ -16,28 +13,27 @@ import java.util.Map; import java.util.TreeMap; -public class EntityTargeting extends RegionalActivityModule implements Listener { +public class EntityTargeting extends RegionalEntityActivityModule { - private final Map limitedTypes = new EnumMap<>(EntityType.class); + private final Map typedDistanceLimits = new EnumMap<>(EntityType.class); private final double globalMaxDistanceSquared; - private final int limit; private final boolean globalDistanceEnabled, perTypeDistanceEnabled; public EntityTargeting() { super("entity-targeting", + false, true, + 8000, 1500.0, 18000, 20000, 14.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ + 120.0, + Map.of(XEntityType.VILLAGER, 1000), + """ Limits entities targeting other entities within a configurable radius\s - and timeframe to help reduce lag by cancelling burst activity hotspots."""); - this.limit = config.getInt(configPath + ".entity-target-event-limit", 8000, """ - Maximum number of times an entity can target another entity within the\s - configured timeframe before the area will be put on cooldown."""); + and timeframe to help reduce lag by cancelling burst activity hotspots.""" + ); this.globalDistanceEnabled = config.getBoolean(configPath + ".distance-limit.global-limit.enable", false); this.globalMaxDistanceSquared = NumberConversions.square( @@ -65,7 +61,7 @@ public EntityTargeting() { try { Double maxDistanceSquared = NumberConversions.square(Double.parseDouble(section.getString(configuredEntity))); EntityType limitedEntity = EntityType.valueOf(configuredEntity); - this.limitedTypes.put(limitedEntity, maxDistanceSquared); + this.typedDistanceLimits.put(limitedEntity, maxDistanceSquared); } catch (NumberFormatException e) { notRecognized(Double.class, configuredEntity); } catch (IllegalArgumentException e) { @@ -76,11 +72,9 @@ public EntityTargeting() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityTarget(EntityTargetEvent event) { - Entity targetEntity = event.getTarget(); - if (targetEntity == null) return; // If entity un-targets an entity, it's good for us. + if (event.getTarget() == null) return; // If entity un-targets an entity, it's good for us. - Location location = event.getEntity().getLocation(); - if (shouldCancelActivity(event, location, limit)) { + if (shouldCancelEntityEvent(event)) { event.setCancelled(true); return; } @@ -91,7 +85,7 @@ private void onEntityTarget(EntityTargetEvent event) { double targetDistanceSquared; try { - targetDistanceSquared = event.getEntity().getLocation().distanceSquared(targetEntity.getLocation()); + targetDistanceSquared = event.getEntity().getLocation().distanceSquared(event.getTarget().getLocation()); } catch (IllegalArgumentException e) { if (logIsEnabled) error("Unable to measure distance between entity and target.", e); return; @@ -102,18 +96,18 @@ private void onEntityTarget(EntityTargetEvent event) { event.setCancelled(true); event.setTarget(null); if (logIsEnabled) info("Cancelled target acquire for entity " + event.getEntityType().name() + " at " + - LocationUtil.toString(location) + + LocationUtil.toString(event.getEntity().getLocation()) + " because target is further than the global limit. Distance: " + Math.sqrt(targetDistanceSquared)); return; } } if (perTypeDistanceEnabled) { - if (limitedTypes.containsKey(event.getEntityType()) && targetDistanceSquared > limitedTypes.get(event.getEntityType())) { + if (typedDistanceLimits.containsKey(event.getEntityType()) && targetDistanceSquared > typedDistanceLimits.get(event.getEntityType())) { event.setCancelled(true); event.setTarget(null); if (logIsEnabled) info("Cancelled target acquire for entity " + event.getEntityType().name() + " at " + - LocationUtil.toString(location) + + LocationUtil.toString(event.getEntity().getLocation()) + " because target further than its configured limit. Distance: " + Math.sqrt(targetDistanceSquared)); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Explosions.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Explosions.java index 47aae4c07..f592a6873 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Explosions.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Explosions.java @@ -8,19 +8,18 @@ public class Explosions extends RegionalActivityModule { - private final int limit; - public Explosions() { super( "explosions", false, + true, + 1000, 1500.0, 6000, 10000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ + 120.0, + """ Limits explosions within a configurable radius and timeframe\s to help reduce lag by cancelling high activity hotspots.\s \s @@ -28,29 +27,27 @@ public Explosions() { \s - A block exploding.\s - An entity exploding.\s - - An entity making the decision to explode."""); - this.limit = config.getInt(configPath + ".explode-event-limit", 500, - "Maximum number of explode events within the configured timeframe\n" + - "before the region will be put on cooldown."); + - An entity making the decision to explode.""" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onExplosionPrime(ExplosionPrimeEvent event) { - if (shouldCancelActivity(event, event.getEntity().getLocation(), limit)) { + if (shouldCancelEvent(event, event.getEntity().getLocation())) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityExplode(EntityExplodeEvent event) { - if (shouldCancelActivity(event, event.getLocation(), limit)) { + if (shouldCancelEvent(event, event.getEntity().getLocation())) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockExplode(BlockExplodeEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelEvent(event, event.getBlock().getLocation())) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/LiquidSpread.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/LiquidSpread.java index 480ba4fae..f0b7cb0d6 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/LiquidSpread.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/LiquidSpread.java @@ -5,22 +5,24 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFromToEvent; -public class LiquidSpread extends RegionalActivityModule { +import java.util.Map; - private final int limit; - private final boolean ignoreDragonEgg; +public class LiquidSpread extends RegionalBlockActivityModule { public LiquidSpread() { super( "liquid-spread", + false, true, + 16000, 1500.0, 18000, 20000, 12.0, - 100.0 - ); - this.config.addComment(configPath+".enable", """ + 100.0, + Map.of( XMaterial.WATER, 4000, + XMaterial.LAVA, 6000), + """ Limits liquid spreading within a configurable radius and timeframe\s to help reduce lag by cancelling high activity hotspots.\s \s @@ -28,18 +30,13 @@ public LiquidSpread() { \s - A lava block spreading by flowing.\s - A water block spreading by flowing.\s - - (optional) A dragon egg is teleporting from one position to another."""); - this.limit = config.getInt(configPath + ".liquid-spread-event-limit", 2400, - "Maximum number of times liquids are allowed to spread within the configured\n" + - "timeframe before they will be put on cooldown."); - this.ignoreDragonEgg = config.getBoolean(configPath + ".ignore-dragon-egg", true); + - A dragon egg is teleporting from one position to another.""" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockFromTo(BlockFromToEvent event) { - if (ignoreDragonEgg && event.getBlock().getType() == XMaterial.DRAGON_EGG.parseMaterial()) return; - - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Noteblocks.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Noteblocks.java deleted file mode 100755 index 7c3945916..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Noteblocks.java +++ /dev/null @@ -1,40 +0,0 @@ -package me.xginko.aef.modules.lagpreventions.regionalactivity; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.NotePlayEvent; - -public class Noteblocks extends RegionalActivityModule { - - private final int limit; - - public Noteblocks() { - super( - "noteblocks", - false, - 1500.0, - 6000, - 10000, - 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ - Limits noteblocks being played within a configurable radius and timeframe\s - to help reduce lag by cancelling high activity hotspots.\s - \s - Examples:\s - \s - - A noteblock is being played through player interaction.\s - - A noteblock is being played through a redstone current."""); - this.limit = config.getInt(configPath + ".noteblock-play-limit", 2800, - "Maximum number of times a noteblock can be played within the configured\n" + - "timeframe before they will be put on cooldown."); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onNotePlay(NotePlayEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { - event.setCancelled(true); - } - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pathfinding.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pathfinding.java index 370e00fe3..5b0fd4738 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pathfinding.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pathfinding.java @@ -7,38 +7,35 @@ import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; import org.bukkit.util.NumberConversions; import java.util.EnumMap; import java.util.Map; import java.util.TreeMap; -public class Pathfinding extends RegionalActivityModule implements Listener { +public class Pathfinding extends RegionalEntityActivityModule { - private final Map limitedTypes = new EnumMap<>(EntityType.class); + private final Map typedDistanceLimits = new EnumMap<>(EntityType.class); private final double globalMaxDistanceSquared; - private final int limit; private final boolean globalDistanceEnabled, perTypeDistanceEnabled; public Pathfinding() { super( "entity-pathfinding", false, + true, + 4000, 1500.0, 6000, 10000, 14.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ + 120.0, + Map.of(XEntityType.VILLAGER, 1000), + """ Limits entities deciding to pathfind to a specific location\s within a configurable radius and timeframe to help reduce lag\s - by cancelling burst activity hotspots."""); - this.limit = config.getInt(configPath + ".entity-pathfind-event-limit", 4000, """ - Maximum number of times an entity can decide to start moving\s - towards a location within the configured timeframe before the\s - area will be put on cooldown."""); + by cancelling burst activity hotspots.""" + ); this.globalDistanceEnabled = config.getBoolean(configPath + ".distance-limit.global-limit.enable", false); this.globalMaxDistanceSquared = NumberConversions.square( @@ -66,7 +63,7 @@ public Pathfinding() { try { Double maxDistanceSquared = NumberConversions.square(Double.parseDouble(section.getString(configuredEntity))); EntityType limitedEntity = EntityType.valueOf(configuredEntity); - this.limitedTypes.put(limitedEntity, maxDistanceSquared); + this.typedDistanceLimits.put(limitedEntity, maxDistanceSquared); } catch (NumberFormatException e) { notRecognized(Double.class, configuredEntity); } catch (IllegalArgumentException e) { @@ -77,7 +74,7 @@ public Pathfinding() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityPathfind(EntityPathfindEvent event) { - if (shouldCancelActivity(event, event.getEntity().getLocation(), limit)) { + if (shouldCancelEntityEvent(event)) { event.setCancelled(true); return; } @@ -105,7 +102,7 @@ private void onEntityPathfind(EntityPathfindEvent event) { } if (perTypeDistanceEnabled) { - if (limitedTypes.containsKey(event.getEntityType()) && targetDistanceSquared > limitedTypes.get(event.getEntityType())) { + if (typedDistanceLimits.containsKey(event.getEntityType()) && targetDistanceSquared > typedDistanceLimits.get(event.getEntityType())) { event.setCancelled(true); if (logIsEnabled) info("Cancelled pathfinding for entity " + event.getEntityType() + " at " + LocationUtil.toString(event.getEntity().getLocation()) + diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pistons.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pistons.java index 9b5a6b2cf..ef650b7e4 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pistons.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pistons.java @@ -1,47 +1,49 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XMaterial; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; -public class Pistons extends RegionalActivityModule { +import java.util.Map; - private final int limit; +public class Pistons extends RegionalBlockActivityModule { public Pistons() { super( "pistons", false, + true, + 2000, 1500.0, 6000, 10000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ + 120.0, + Map.of( XMaterial.PISTON, 1000, + XMaterial.STICKY_PISTON, 1000), + """ Limits piston movement within a configurable radius and timeframe\s to help reduce lag by cancelling high activity hotspots.\s \s Examples:\s \s - A piston extends.\s - - A piston retracts."""); - this.limit = config.getInt(configPath + ".piston-movement-limit", 1000, - "Maximum number of piston extend and/or retracts within the\n" + - "configured timeframe."); + - A piston retracts.""" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPistonExtend(BlockPistonExtendEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPistonRetract(BlockPistonRetractEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Redstone.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Redstone.java index 4d34efe38..635144dad 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Redstone.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Redstone.java @@ -1,24 +1,31 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XMaterial; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockRedstoneEvent; -public class Redstone extends RegionalActivityModule { +import java.util.Map; - private final int limit; +public class Redstone extends RegionalBlockActivityModule { public Redstone() { super( "redstone", + false, true, + 6000, 1500.0, 18000, 20000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ + 120.0, + Map.of( XMaterial.SCULK_SENSOR, 500, + XMaterial.SCULK_SHRIEKER, 300, + XMaterial.CALIBRATED_SCULK_SENSOR, 500, + XMaterial.OBSERVER, 1500, + XMaterial.COMPARATOR, 2000), + """ Limits redstone activity within a configurable radius and timeframe\s to help reduce lag by cancelling high activity hotspots.\s \s @@ -26,14 +33,13 @@ public Redstone() { \s - A redstone current changes.\s - A redstone block gets powered on.\s - - A redstone block gets powered off."""); - this.limit = config.getInt(configPath + ".redstone-event-limit", 6000, - "Maximum number of redstone events within configured timeframe."); + - A redstone block gets powered off.""" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockRedstone(BlockRedstoneEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setNewCurrent(0); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalActivityModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalActivityModule.java index cca7ae78d..dd07c50fd 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalActivityModule.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalActivityModule.java @@ -4,14 +4,19 @@ import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.models.BlockRegion2D; +import me.xginko.aef.utils.models.Lazy; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; import java.time.Duration; +import java.util.EnumMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -22,109 +27,148 @@ */ public abstract class RegionalActivityModule extends AEFModule implements Listener { - protected final Cache regionDataCache; - protected final long pauseTimeMillis; + protected final long cacheTimeMillis, pauseTimeMillis; protected final double checkRadius, pauseTPS, pauseMSPT; + protected final int totalActivityLimit; protected final boolean logIsEnabled; + protected Cache regionDataCache; + public RegionalActivityModule( - String subConfigPath, boolean deflogEnabled, double defCheckRadius, + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, double defCheckRadius, int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT ) { - super("lag-preventions.regional-activity."+subConfigPath); - String configPath = "lag-preventions.regional-activity."+subConfigPath; + this(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, + defPauseMillis, defCacheMillis, defPauseTPS, defPauseMSPT, null); + } + + public RegionalActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int defTotalLimit, double defCheckRadius, + int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, String comment) { + super("lag-preventions.regional-activity."+subConfigPath, defEnabled, comment); + String configPath = "lag-preventions.regional-activity." + subConfigPath; this.logIsEnabled = config.getBoolean(configPath + ".log", deflogEnabled); + this.totalActivityLimit = config.getInt(configPath + ".total-limit", defTotalLimit, + "The maximum amount of measured activity of this type that is allowed\n" + + "to happen within the configured timeframe (cache-millis).\n" + + "This value should always be higher than any of the configured per type limits."); this.checkRadius = config.getDouble(configPath + ".check-radius-blocks", defCheckRadius, "The radius in blocks in which activity will be grouped together and measured."); this.pauseTimeMillis = config.getInt(configPath + ".pause-time-millis", defPauseMillis, "The time in milliseconds all related activity will be blocked if it exceeded\n" + "the configured limit."); - this.regionDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis( - config.getInt(configPath + ".data-keep-time-millis", defCacheMillis, - "The time in milliseconds before a region and its data will be expired\n" + - "if no activity has been detected.\n" + - "For proper functionality, needs to be at least as long as your pause time."))).build(); + this.cacheTimeMillis = Math.max(100L, config.getInt(configPath + ".data-keep-time-millis", defCacheMillis, + "The time in milliseconds before a region and its data will be expired\n" + + "if no activity has been detected.\n" + + "For proper functionality, needs to be at least as long as your pause time.")); this.pauseTPS = config.getDouble(configPath + ".pause-TPS", defPauseTPS, "The TPS at which to cancel the physics entirely."); this.pauseMSPT = config.getDouble(configPath + ".pause-MSPT", defPauseMSPT, "The MSPT at which to cancel the physics entirely."); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void enable() { + regionDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } @Override public void disable() { HandlerList.unregisterAll(this); - regionDataCache.invalidateAll(); + if (regionDataCache != null) { + regionDataCache.invalidateAll(); + regionDataCache.cleanUp(); + regionDataCache = null; + } + } + + protected @NotNull BlockRegion2D getRegion(Location location) { + // Find and return region containing this location + for (Map.Entry regionDataEntry : regionDataCache.asMap().entrySet()) { + if (regionDataEntry.getKey().contains(location)) { + return regionDataEntry.getKey(); + } + } + // Create and cache region if none exists + BlockRegion2D region = BlockRegion2D.of(location.getWorld(), location.getX(), location.getZ(), checkRadius); + regionDataCache.put(region, new RegionData(region)); + return region; } protected @NotNull RegionalActivityModule.RegionData getRegionData(Location location) { return regionDataCache.get(getRegion(location), RegionData::new); } - public boolean shouldCancelActivity(Event event, Location location, int limit) { - double tps = AnarchyExploitFixes.getTickReporter().getTPS(); - double mspt = AnarchyExploitFixes.getTickReporter().getMSPT(); + protected boolean shouldCancelEvent(T event, Location location) { + return shouldCancelBecauseLagging(event) || shouldCancelBecauseTotalActivity(event, location); + } - if (tps <= pauseTPS || mspt >= pauseMSPT) { + protected boolean shouldCancelBecauseLagging(T event) { + double ticksPerSecond = AnarchyExploitFixes.tickReporter().getTPS(); + double milliSecondsPerTick = AnarchyExploitFixes.tickReporter().getMSPT(); + if (ticksPerSecond <= pauseTPS || milliSecondsPerTick >= pauseMSPT) { if (logIsEnabled) info("Cancelling " + event.getClass().getSimpleName() + " because server is lagging." + - " (tps="+String.format("%.4f", tps)+" | mspt="+String.format("%.4f", mspt)+")"); + " (tps="+String.format("%.4f", ticksPerSecond)+" | mspt="+String.format("%.4f", milliSecondsPerTick)+")"); return true; } + return false; + } + protected boolean shouldCancelBecauseTotalActivity(T event, Location location) { RegionData regionData = getRegionData(location); - if (regionData.resumeTime.get() > System.currentTimeMillis()) { + if (regionData.getTotalActivityData().resumeTimeMillis.get() > System.currentTimeMillis()) { + if (logIsEnabled) info("Cancelling " + event.getClass().getSimpleName() + " indiscriminately at " + + LocationUtil.toString(location) + " because the region exceeded the total activity limit."); return true; } - if (regionData.activityCount.incrementAndGet() > limit) { + if (regionData.getTotalActivityData().activityCount.incrementAndGet() > totalActivityLimit) { if (logIsEnabled) { info( "Disabling in a radius of " + checkRadius + " blocks from center at " + "x=" + regionData.region.getCenterX() + ", z=" + regionData.region.getCenterZ() + " in world " + location.getWorld().getName() + " for " + pauseTimeMillis + "ms, " + "because of too high activity within the configured timeframe: " + - regionData.activityCount + " (limit: " + limit + ")"); + regionData.getTotalActivityData().activityCount + " (limit: " + totalActivityLimit + ")"); } - regionData.resumeTime.set(System.currentTimeMillis() + pauseTimeMillis); - regionData.activityCount.set(0); // Reset count when region is cooling down + regionData.getTotalActivityData().resumeTimeMillis.set(System.currentTimeMillis() + pauseTimeMillis); + regionData.getTotalActivityData().activityCount.set(0); // Reset count when region is cooling down return true; } return false; } - public @NotNull BlockRegion2D getRegion(Location location) { - // Find and return region containing this location - for (Map.Entry regionDataEntry : regionDataCache.asMap().entrySet()) { - if (regionDataEntry.getKey().contains(location)) { - return regionDataEntry.getKey(); - } - } - // Create and cache region if none exists - BlockRegion2D region = BlockRegion2D.of(location.getWorld(), location.getX(), location.getZ(), checkRadius); - regionDataCache.put(region, new RegionData(region)); - return region; - } - protected static class RegionData { public final BlockRegion2D region; - public final AtomicLong resumeTime; - public final AtomicInteger activityCount; + private final ActivityData totalActivityData; + private final Lazy> blockActivityData; + private final Lazy> entityActivityData; public RegionData(BlockRegion2D region) { this.region = region; - this.activityCount = new AtomicInteger(0); - this.resumeTime = new AtomicLong(0L); + this.totalActivityData = new ActivityData(); + this.blockActivityData = Lazy.of(() -> new EnumMap<>(Material.class)); + this.entityActivityData = Lazy.of(() -> new EnumMap<>(EntityType.class)); + } + + public ActivityData getTotalActivityData() { + return totalActivityData; + } + + public ActivityData getBlockActivityData(Material material) { + return blockActivityData.get().computeIfAbsent(material, k -> new ActivityData()); + } + + public ActivityData getEntityActivityData(EntityType entityType) { + return entityActivityData.get().computeIfAbsent(entityType, k -> new ActivityData()); + } + + public static class ActivityData { + public final AtomicInteger activityCount = new AtomicInteger(); + public final AtomicLong resumeTimeMillis = new AtomicLong(); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalBlockActivityModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalBlockActivityModule.java new file mode 100644 index 000000000..e3b1483d8 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalBlockActivityModule.java @@ -0,0 +1,93 @@ +package me.xginko.aef.modules.lagpreventions.regionalactivity; + +import com.cryptomorin.xseries.XMaterial; +import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.utils.LocationUtil; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.event.block.BlockEvent; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +/** + * Credits to the initial idea of measuring burst activity within a certain region + * of the world go to kumori (Soft1k) of 3b3t.org. + */ +public abstract class RegionalBlockActivityModule extends RegionalActivityModule { + + protected final Map typedActivityLimit = new EnumMap<>(Material.class); + + public RegionalBlockActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, double defCheckRadius, + int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, + Map defaultTypeSettings + ) { + this(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, defPauseMillis, defCacheMillis, + defPauseTPS, defPauseMSPT, defaultTypeSettings, null); + } + + public RegionalBlockActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, + double defCheckRadius, int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, + Map defaultTypeSettings, String comment) { + super(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, defPauseMillis, defCacheMillis, defPauseTPS, defPauseMSPT, comment); + Map defaultKV = new HashMap<>(defaultTypeSettings.size()); + for (Map.Entry entry : defaultTypeSettings.entrySet()) { + if (entry.getKey().isSupported()) { + defaultKV.put(entry.getKey().get().name(), entry.getValue()); + } + } + ConfigSection typedSection = config.getConfigSection(configPath + ".typed-limits", defaultKV, """ + Set activity limits per Material (BlockType). + Note that you cannot set a value higher than the one configured in total-limit."""); + for (String configuredMaterial : typedSection.getKeys(false)) { + try { + typedActivityLimit.put(Material.valueOf(configuredMaterial), Integer.parseInt(typedSection.getString(configuredMaterial))); + } catch (NumberFormatException e) { + notRecognized(Integer.class, typedSection.getString(configuredMaterial)); + }catch (IllegalArgumentException e) { + notRecognized(GameMode.class, configuredMaterial); + } + } + } + + protected boolean shouldCancelBlockEvent(T blockEvent) { + return shouldCancelEvent(blockEvent, blockEvent.getBlock().getLocation()) || shouldCancelBecauseTypeActivity(blockEvent); + } + + protected boolean shouldCancelBecauseTypeActivity(T blockEvent) { + if (!typedActivityLimit.containsKey(blockEvent.getBlock().getType())) { + return false; + } + + int typeLimit = typedActivityLimit.get(blockEvent.getBlock().getType()); + RegionData regionData = getRegionData(blockEvent.getBlock().getLocation()); + RegionData.ActivityData activityData = regionData.getBlockActivityData(blockEvent.getBlock().getType()); + + if (activityData.resumeTimeMillis.get() > System.currentTimeMillis()) { + if (logIsEnabled) { + info( "Cancelling " + blockEvent.getClass().getSimpleName() + " for " + blockEvent.getBlock().getType().name() + + " at " + LocationUtil.toString(blockEvent.getBlock().getLocation()) + " because it exceeded its " + + "activity (limit: " + typeLimit + ")."); + } + return true; + } + + if (activityData.activityCount.incrementAndGet() > typeLimit) { + if (logIsEnabled) { + warn( "Disabling " + blockEvent.getBlock().getType().name() + " in a radius of " + checkRadius + + " blocks from center at x=" + regionData.region.getCenterX() + ", z=" + regionData.region.getCenterZ() + + " in world " + blockEvent.getBlock().getWorld().getName() + " for " + pauseTimeMillis + + "ms, because of too high activity within the configured timeframe: " + + activityData.activityCount + " (limit: " + typeLimit + ")"); + } + activityData.resumeTimeMillis.set(System.currentTimeMillis() + pauseTimeMillis); + activityData.activityCount.set(0); // Reset count when region is cooling down + return true; + } + + return false; + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalEntityActivityModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalEntityActivityModule.java new file mode 100644 index 000000000..23fefbe4d --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalEntityActivityModule.java @@ -0,0 +1,93 @@ +package me.xginko.aef.modules.lagpreventions.regionalactivity; + +import com.cryptomorin.xseries.XEntityType; +import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.utils.LocationUtil; +import org.bukkit.GameMode; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.EntityEvent; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +/** + * Credits to the initial idea of measuring burst activity within a certain region + * of the world go to kumori (Soft1k) of 3b3t.org. + */ +public abstract class RegionalEntityActivityModule extends RegionalActivityModule { + + protected final Map typedActivityLimit = new EnumMap<>(EntityType.class); + + public RegionalEntityActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, double defCheckRadius, + int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, + Map defaultTypeSettings + ) { + this(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, defPauseMillis, defCacheMillis, + defPauseTPS, defPauseMSPT, defaultTypeSettings, null); + } + + public RegionalEntityActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, + double defCheckRadius, int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, + Map defaultTypeSettings, String comment) { + super(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, defPauseMillis, defCacheMillis, defPauseTPS, defPauseMSPT, comment); + Map defaultKV = new HashMap<>(defaultTypeSettings.size()); + for (Map.Entry entry : defaultTypeSettings.entrySet()) { + if (entry.getKey().isSupported()) { + defaultKV.put(entry.getKey().get().name(), entry.getValue()); + } + } + ConfigSection typedSection = config.getConfigSection(configPath + ".typed-limits", defaultKV, """ + Set activity limits per EntityType. + Note that you cannot set a value higher than the one configured in total-limit."""); + for (String configuredEntity : typedSection.getKeys(false)) { + try { + typedActivityLimit.put(EntityType.valueOf(configuredEntity), Integer.parseInt(typedSection.getString(configuredEntity))); + } catch (NumberFormatException e) { + notRecognized(Integer.class, typedSection.getString(configuredEntity)); + }catch (IllegalArgumentException e) { + notRecognized(GameMode.class, configuredEntity); + } + } + } + + protected boolean shouldCancelEntityEvent(T entityEvent) { + return shouldCancelEvent(entityEvent, entityEvent.getEntity().getLocation()) || shouldCancelBecauseTypeActivity(entityEvent); + } + + protected boolean shouldCancelBecauseTypeActivity(T entityEvent) { + if (!typedActivityLimit.containsKey(entityEvent.getEntity().getType())) { + return false; + } + + int typeLimit = typedActivityLimit.get(entityEvent.getEntityType()); + RegionData regionData = getRegionData(entityEvent.getEntity().getLocation()); + RegionData.ActivityData activityData = regionData.getEntityActivityData(entityEvent.getEntityType()); + + if (activityData.resumeTimeMillis.get() > System.currentTimeMillis()) { + if (logIsEnabled) { + info( "Cancelling " + entityEvent.getClass().getSimpleName() + " for " + entityEvent.getEntityType().name() + + " at " + LocationUtil.toString(entityEvent.getEntity().getLocation()) + " because it exceeded its " + + "activity (limit: " + typeLimit + ")."); + } + return true; + } + + if (activityData.activityCount.incrementAndGet() > typeLimit) { + if (logIsEnabled) { + warn( "Disabling " + entityEvent.getEntityType().name() + " in a radius of " + checkRadius + + " blocks from center at x=" + regionData.region.getCenterX() + ", z=" + regionData.region.getCenterZ() + + " in world " + entityEvent.getEntity().getWorld().getName() + " for " + pauseTimeMillis + "ms, " + + "because of too high activity within the configured timeframe: " + + activityData.activityCount + " (limit: " + typeLimit + ")"); + } + activityData.resumeTimeMillis.set(System.currentTimeMillis() + pauseTimeMillis); + activityData.activityCount.set(0); // Reset count when region is cooling down + return true; + } + + return false; + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkActivity.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkActivity.java deleted file mode 100644 index 0d4896f80..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkActivity.java +++ /dev/null @@ -1,79 +0,0 @@ -package me.xginko.aef.modules.lagpreventions.regionalactivity; - -import com.cryptomorin.xseries.XMaterial; -import org.bukkit.Material; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockPhysicsEvent; -import org.bukkit.event.block.BlockRedstoneEvent; - -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class SculkActivity extends RegionalActivityModule { - - private final Set sculkBlocks; - private final int limit; - - public SculkActivity() { - super( - "sculk-sensor", - true, - 1500.0, - 18000, - 20000, - 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", - "Limits sculk activity within a configurable radius and timeframe\n" + - "to help reduce lag by cancelling high activity hotspots.\n" + - "\n" + - "Examples:\n" + - "\n" + - "- A redstone current changes for a sculk sensor.\n" + - "- A physics check is being performed for a sculk sensor."); - this.limit = config.getInt(configPath + ".sculk-event-limit", 800, - "Maximum number of sculk events within configured timeframe."); - List defaults = Stream.of( - XMaterial.SCULK_SENSOR, - XMaterial.SCULK_SHRIEKER, - XMaterial.CALIBRATED_SCULK_SENSOR) - .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) - .map(Enum::name) - .collect(Collectors.toList()); - this.sculkBlocks = config.getList(configPath + ".sculk-blocks", defaults) - .stream() - .map(configuredType -> { - try { - return Material.valueOf(configuredType); - } catch (IllegalArgumentException e) { - notRecognized(Material.class, configuredType); - return null; - } - }) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockRedstone(BlockRedstoneEvent event) { - if (!sculkBlocks.contains(event.getBlock().getType())) return; - - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { - event.setNewCurrent(0); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockPhysics(BlockPhysicsEvent event) { - if (!sculkBlocks.contains(event.getBlock().getType())) return; - - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { - event.setCancelled(true); - } - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkBloom.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkBloom.java index 0997ab64c..f89fa5ef6 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkBloom.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkBloom.java @@ -1,24 +1,27 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import me.xginko.aef.utils.LocationUtil; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.SculkBloomEvent; public class SculkBloom extends RegionalActivityModule { - private final int limit; + private final int maxCharge; + private final boolean chargeLimitEnabled; public SculkBloom() { super( "sculk-bloom", false, + true, + 600, 1500.0, 6000, 10000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", """ + 120.0, + """ Limits sculk blooming within a configurable radius and timeframe\s to help reduce lag by cancelling high activity hotspots.\s \s @@ -26,14 +29,31 @@ public SculkBloom() { \s - An entity was killed and dropped experience within an 8-block\s radius of a SculkCatalyst.\s - - A plugin used SculkCatalyst.bloom(Block, int)"""); - this.limit = config.getInt(configPath + ".sculk-bloom-limit", 300, - "Maximum number of sculk bloom events within the configured timeframe."); + - A plugin used SculkCatalyst.bloom(Block, int)""" + ); + + this.chargeLimitEnabled = config.getBoolean(configPath + ".charge-limit.enable", false, """ + Limit the charge power of sculk blooming, which determines to how many blocks + the sculk will spread after an entity dies near a catalyst."""); + this.maxCharge = Math.max(0, Math.min(1000, config.getInt(configPath + ".charge-limit.max-charge", 20, """ + Typically, charges will be set to the exp reward of a mob (DroppedExp), + which is usually 3-5 for animals, and 5-10 for the average mob (up to 50 for wither skeletons). + Roughly speaking, for each charge, 1 more sculk block will be placed. + Can only be between 0-1000."""))); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onSkulkBloom(SculkBloomEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (chargeLimitEnabled && event.getCharge() > maxCharge) { + if (logIsEnabled) { + info( "Limiting Sculk charge limit (charge=" + event.getCharge() + "|max=" + maxCharge + ") " + + "at " + LocationUtil.toString(event.getBlock().getLocation())); + } + event.setCharge(maxCharge); + return; + } + + if (shouldCancelEvent(event, event.getBlock().getLocation())) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/AutoBedOrSpigot5988.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/AutoBedOrSpigot5988.java index 5799fa567..c1a442ecc 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/AutoBedOrSpigot5988.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/AutoBedOrSpigot5988.java @@ -10,19 +10,18 @@ public class AutoBedOrSpigot5988 extends AEFModule implements Listener { public AutoBedOrSpigot5988() { - super("misc.auto-bed"); - config.addComment(configPath+ ".enable", - "Re-enables SPIGOT-5988, also known as 'auto-bed'\n"+ - "From Minecraft version 1.16 (≈June 2020) to version 1.17.1(≈October 2021)\n" + - "there was a bug (SPIGOT-5988) which did not reset the respawn point of the\n" + - "player after death, if his bed was blocked with a shulker.\n" + - "After dying a second time, the player will be back at his bed again.\n" + - "This bug persisted from the Spigot server to Paper and all its forks until\n" + - "October 2021, after which it was fixed by the Spigot development team.\n" + - "Attempts by players to reach out to Spigot to allow them to disable the patch\n" + - "that fixes the SPIGOT-5988 bug have failed.\n" + - "Demonstration of how the patch works:\n" + - "https://www.youtube.com/watch?v=3y5SbQXzMss"); + super("misc.auto-bed", false,""" + Re-enables SPIGOT-5988, also known as 'auto-bed' + From Minecraft version 1.16 (≈June 2020) to version 1.17.1(≈October 2021) + there was a bug (SPIGOT-5988) which did not reset the respawn point of the + player after death, if his bed was blocked with a shulker. + After dying a second time, the player will be back at his bed again. + This bug persisted from the Spigot server to Paper and all its forks until + October 2021, after which it was fixed by the Spigot development team. + Attempts by players to reach out to Spigot to allow them to disable the patch + that fixes the SPIGOT-5988 bug have failed. + Demonstration of how the patch works: + https://www.youtube.com/watch?v=3y5SbQXzMss"""); } @Override @@ -35,11 +34,6 @@ public void disable() { HandlerList.unregisterAll(this); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerSetSpawn(com.destroystokyo.paper.event.player.PlayerSetSpawnEvent event) { if (event.getCause() == PlayerSetSpawnEvent.Cause.PLUGIN || event.getCause() == PlayerSetSpawnEvent.Cause.COMMAND) return; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/FirstJoinMessages.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/FirstJoinMessages.java index a951497ab..0349eba52 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/FirstJoinMessages.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/FirstJoinMessages.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.misc; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFKey; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.enums.AEFKey; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; @@ -24,12 +24,11 @@ public class FirstJoinMessages extends AEFModule implements Listener { private final boolean logFirstJoin; public FirstJoinMessages() { - super("misc.join-leave-messages.first-join-messages"); - this.totalPlayers = new AtomicInteger(0); - this.config.addComment(configPath + ".enable", + super("misc.join-leave-messages.first-join-messages", false, "Configure message in lang folder.\n" + - "You can hide yourself and other players using the permission:\n" + - AEFPermission.SILENT_JOIN.string()); + "You can hide yourself and other players using the permission:\n" + + AEFPermission.SILENT_JOIN.node()); + this.totalPlayers = new AtomicInteger(0); this.logFirstJoin = config.getBoolean(configPath + ".show-in-console", true); } @@ -42,11 +41,6 @@ public void enable() { .thenRun(() -> plugin.getServer().getPluginManager().registerEvents(this, plugin)); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -57,7 +51,7 @@ public void disable() { private void onPlayerJoin(PlayerJoinEvent event) { final Player joiningPlayer = event.getPlayer(); if (joiningPlayer.hasPlayedBefore()) return; - if (joiningPlayer.hasPermission(AEFPermission.SILENT_JOIN.string())) return; + if (AnarchyExploitFixes.permissions().permissionValue(joiningPlayer, AEFPermission.SILENT_JOIN.node()).toBoolean()) return; final int joiningPlayersNumber = totalPlayers.incrementAndGet(); @@ -85,7 +79,7 @@ private void onPlayerJoin(PlayerJoinEvent event) { if (logFirstJoin) { for (Component line : AnarchyExploitFixes.getLang(joiningPlayer.locale()).misc_firstJoinMessage) { - AnarchyExploitFixes.getUnprefixedLogger().info(line + AnarchyExploitFixes.unprefixedLogger().info(line .replaceText(TextReplacementConfig.builder() .matchLiteral("%player%") .replacement(joiningPlayer.name()) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/JoinLeaveMessages.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/JoinLeaveMessages.java index 61878c07d..798d8a029 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/JoinLeaveMessages.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/JoinLeaveMessages.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.misc; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFKey; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.enums.AEFKey; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; @@ -18,15 +18,13 @@ public class JoinLeaveMessages extends AEFModule implements Listener { - private final boolean connectionMsgsOnByDefault, showInConsole, firstJoinEnabled; + private final boolean showInConsole, firstJoinEnabled; public JoinLeaveMessages() { - super("misc.join-leave-messages"); - config.addComment(configPath + ".enable", + super("misc.join-leave-messages", false, "If you want to hide yourself or someone else when logging\n" + - "into the game, use these permissions:\n" + - AEFPermission.SILENT_JOIN.string() + ", " + AEFPermission.SILENT_LEAVE.string()); - this.connectionMsgsOnByDefault = config.connectionMsgsAreOnByDefault; + "into the game, use these permissions:\n" + + AEFPermission.SILENT_JOIN.node() + ", " + AEFPermission.SILENT_LEAVE.node()); this.showInConsole = config.getBoolean(configPath + ".show-in-console", false); this.firstJoinEnabled = config.getBoolean(configPath + ".first-join-messages.enable", false); } @@ -36,11 +34,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -51,14 +44,14 @@ public void disable() { private void onPlayerJoinEvent(PlayerJoinEvent event) { event.joinMessage(null); final Player joiningPlayer = event.getPlayer(); - if (joiningPlayer.hasPermission(AEFPermission.SILENT_JOIN.string())) return; + if (AnarchyExploitFixes.permissions().permissionValue(joiningPlayer, AEFPermission.SILENT_JOIN.node()).toBoolean()) return; if (firstJoinEnabled && !joiningPlayer.hasPlayedBefore()) return; for (final Player onlinePlayer : plugin.getServer().getOnlinePlayers()) { onlinePlayer.getScheduler().execute(plugin, () -> { final PersistentDataContainer dataContainer = onlinePlayer.getPersistentDataContainer(); if ( - !dataContainer.has(AEFKey.CONNECT_MSG_TOGGLE.getKey()) ? connectionMsgsOnByDefault : + !dataContainer.has(AEFKey.CONNECT_MSG_TOGGLE.getKey()) ? config.connectionMsgsAreOnByDefault : dataContainer.get(AEFKey.CONNECT_MSG_TOGGLE.getKey(), PersistentDataType.BOOLEAN) ) { onlinePlayer.sendMessage(AnarchyExploitFixes.getLang(onlinePlayer.locale()).misc_joinMessage @@ -68,7 +61,7 @@ private void onPlayerJoinEvent(PlayerJoinEvent event) { } if (showInConsole) { - AnarchyExploitFixes.getUnprefixedLogger().info(AnarchyExploitFixes.getLang(joiningPlayer.locale()).misc_joinMessage + AnarchyExploitFixes.unprefixedLogger().info(AnarchyExploitFixes.getLang(joiningPlayer.locale()).misc_joinMessage .replaceText(TextReplacementConfig.builder().matchLiteral("%player%").replacement(joiningPlayer.name()).build()) .append(Component.text(" (" + joiningPlayer.locale() + ")"))); } @@ -79,14 +72,14 @@ private void onPlayerJoinEvent(PlayerJoinEvent event) { private void onPlayerLeaveEvent(PlayerQuitEvent event) { event.quitMessage(null); final Player leavingPlayer = event.getPlayer(); - if (leavingPlayer.hasPermission(AEFPermission.SILENT_LEAVE.string())) return; + if (AnarchyExploitFixes.permissions().permissionValue(leavingPlayer, AEFPermission.SILENT_LEAVE.node()).toBoolean()) return; for (final Player onlinePlayer : plugin.getServer().getOnlinePlayers()) { onlinePlayer.getScheduler().execute(plugin, () -> { if (onlinePlayer.getUniqueId().equals(leavingPlayer.getUniqueId())) return; final PersistentDataContainer dataContainer = onlinePlayer.getPersistentDataContainer(); if ( - !dataContainer.has(AEFKey.CONNECT_MSG_TOGGLE.getKey()) ? connectionMsgsOnByDefault : + !dataContainer.has(AEFKey.CONNECT_MSG_TOGGLE.getKey()) ? config.connectionMsgsAreOnByDefault : dataContainer.get(AEFKey.CONNECT_MSG_TOGGLE.getKey(), PersistentDataType.BOOLEAN) ) { onlinePlayer.sendMessage(AnarchyExploitFixes.getLang(onlinePlayer.locale()).misc_leaveMessage @@ -96,7 +89,7 @@ private void onPlayerLeaveEvent(PlayerQuitEvent event) { } if (showInConsole) { - AnarchyExploitFixes.getUnprefixedLogger().info(AnarchyExploitFixes.getLang(leavingPlayer.locale()).misc_leaveMessage + AnarchyExploitFixes.unprefixedLogger().info(AnarchyExploitFixes.getLang(leavingPlayer.locale()).misc_leaveMessage .replaceText(TextReplacementConfig.builder().matchLiteral("%player%").replacement(leavingPlayer.name()).build()) .append(Component.text(" (" + leavingPlayer.locale() + ")"))); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/MaskKickMessages.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/MaskKickMessages.java index a1bd32ea0..dc1bbc63e 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/MaskKickMessages.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/MaskKickMessages.java @@ -11,7 +11,7 @@ public class MaskKickMessages extends AEFModule implements Listener { public MaskKickMessages() { - super("misc.kicks.mask-kick-messages"); + super("misc.kicks.mask-kick-messages", false); config.addComment(configPath, "Configure mask message in lang folder."); } @@ -20,11 +20,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/PreventMessageKick.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/PreventMessageKick.java index 63ba6f974..e1882ec31 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/PreventMessageKick.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/misc/PreventMessageKick.java @@ -18,7 +18,7 @@ public class PreventMessageKick extends AEFModule implements Listener { private final Set kickMessagesToListenTo; public PreventMessageKick() { - super("misc.kicks.prevent-message-kick"); + super("misc.kicks.prevent-message-kick", false); config.addComment(configPath + ".enable", "Cancels the kick for specific kick messages."); this.kickMessagesToListenTo = config.getList(configPath + ".kick-messages-to-listen-to", List.of("Kicked for spamming", "Stop spamming!")) @@ -32,11 +32,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BedTrap.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BedTrap.java new file mode 100755 index 000000000..08d83d2f3 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BedTrap.java @@ -0,0 +1,138 @@ +package me.xginko.aef.modules.packets; + +import com.destroystokyo.paper.event.player.PlayerPostRespawnEvent; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.event.PacketListenerPriority; +import com.github.retrooper.packetevents.event.PacketReceiveEvent; +import com.github.retrooper.packetevents.protocol.ConnectionState; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; +import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus; +import me.xginko.aef.utils.PlatformUtil; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; + +import java.time.Duration; +import java.util.Collections; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class BedTrap extends PacketModule implements Listener { + + private final long timeInSeconds; + private final int maxDeathsPerTime; + private final boolean shouldLog; + + private Set deadPlayers; + private Cache playerDeathNearBedCount; + + public BedTrap() { + super("preventions.anti-bed-trap", false, PacketListenerPriority.MONITOR, """ + Resets a players bed respawn they die too many times within\s + a certain timeframe."""); + this.maxDeathsPerTime = config.getInt(configPath + ".max-deaths-per-time", 7, """ + Amount of times player can die until he is determined as bed-trapped."""); + this.timeInSeconds = Math.max(1, config.getInt(configPath + ".time-in-seconds", 5, """ + "Time until death counter will be reset again.""")); + this.shouldLog = config.getBoolean(configPath+".log", false); + } + + @Override + public void enable() { + deadPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>()); + playerDeathNearBedCount = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(timeInSeconds)).build(); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + if (PlatformUtil.isFolia()) { + PacketEvents.getAPI().getEventManager().registerListener(asAbstract); + } + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + if (PlatformUtil.isFolia()) { + PacketEvents.getAPI().getEventManager().unregisterListener(asAbstract); + } + if (deadPlayers != null) { + deadPlayers.clear(); + deadPlayers = null; + } + if (playerDeathNearBedCount != null) { + playerDeathNearBedCount.invalidateAll(); + playerDeathNearBedCount.cleanUp(); + playerDeathNearBedCount = null; + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onPlayerDeath(PlayerDeathEvent event) { + if (PlatformUtil.isFolia()) { + deadPlayers.add(event.getPlayer().getUniqueId()); + } + } + + @SuppressWarnings("deprecation") + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPlayerPostRespawn(PlayerPostRespawnEvent event) { + if (!event.isBedSpawn()) return; + + if (playerDeathNearBedCount.get(event.getPlayer().getUniqueId(), k -> new AtomicInteger()).incrementAndGet() <= maxDeathsPerTime) { + return; + } + + event.getPlayer().getScheduler().execute(plugin, () -> { + try { + event.getPlayer().setRespawnLocation(null, true); + } catch (NoSuchMethodError e) { + event.getPlayer().setBedSpawnLocation(null, true); + } + if (shouldLog) info("Reset bed respawn of potentially bed-trapped player '" + event.getPlayer().getName() + "'"); + }, null, 1L); + } + + /** + * Needed on folia since PlayerPostRespawnEvent does not fire + */ + @Override + @SuppressWarnings("deprecation") + public void onPacketReceive(PacketReceiveEvent event) { + if (event.isCancelled()) return; + if (event.getConnectionState() != ConnectionState.PLAY) return; + if (event.getPacketType() != PacketType.Play.Client.CLIENT_STATUS) return; + if (new WrapperPlayClientClientStatus(event).getAction() != WrapperPlayClientClientStatus.Action.PERFORM_RESPAWN) return; + + Player player = event.getPlayer(); + if (player == null) return; + + if (!deadPlayers.contains(player.getUniqueId()) && !player.isDead()) { + return; + } + + player.getScheduler().execute(plugin, () -> { + Location potentialBedSpawn = player.getPotentialBedLocation(); + if (potentialBedSpawn == null || potentialBedSpawn.distanceSquared(player.getLocation()) > 16) return; + + if (playerDeathNearBedCount.get(player.getUniqueId(), k -> new AtomicInteger()).incrementAndGet() <= maxDeathsPerTime) { + return; + } + + try { + player.setRespawnLocation(null, true); + } catch (NoSuchMethodError e) { + player.setBedSpawnLocation(null, true); + } + + if (shouldLog) info("Reset bed respawn of potentially bed-trapped player '" + player.getName() + "'"); + + deadPlayers.remove(player.getUniqueId()); + }, null, 20L); + } +} \ No newline at end of file diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BeehiveCoordinates.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BeehiveCoordinates.java index f67519012..1eb914aa5 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BeehiveCoordinates.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BeehiveCoordinates.java @@ -16,8 +16,7 @@ public class BeehiveCoordinates extends PacketModule { private final String[] entityDataTagsToRemove; public BeehiveCoordinates() { - super("patches.remove-beehive-coordinates", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", """ + super("patches.remove-beehive-coordinates", true, PacketListenerPriority.HIGHEST, """ Patches an exploit that allows players to obtain another player's\s coordinates by trading them for Beehives or Beenests.\s If the traded item contains any bees, the stored bee's NBT data can\s @@ -35,11 +34,6 @@ public BeehiveCoordinates() { .toArray(new String[0]); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void onPacketSend(PacketSendEvent event) { if (event.isCancelled()) return; @@ -58,7 +52,7 @@ public void onPacketSend(PacketSendEvent event) { } } - if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) { + else if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) { WrapperPlayServerWindowItems packet = new WrapperPlayServerWindowItems(event); for (int i = 0; i < packet.getItems().size(); i++) { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BigMessages.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BigMessages.java new file mode 100755 index 000000000..2c353ac08 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/BigMessages.java @@ -0,0 +1,51 @@ +package me.xginko.aef.modules.packets; + +import com.github.retrooper.packetevents.event.PacketListenerPriority; +import com.github.retrooper.packetevents.event.PacketReceiveEvent; +import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; + +import java.nio.charset.StandardCharsets; + +public class BigMessages extends PacketModule { + + private final int charLimit; + private final boolean log, kick; + + public BigMessages() { + super("patches.message-char-limit", true, PacketListenerPriority.HIGHEST, """ + Sets a character limit for command and message packets to prevent a lag exploit."""); + this.charLimit = config.getInt(configPath + ".max-characters", 256); + this.log = config.getBoolean(configPath + ".log", false); + this.kick = config.getBoolean(configPath + ".kick-player", false); + } + + @Override + public void onPacketReceive(PacketReceiveEvent event) { + if (event.isCancelled()) return; + + if ( + event.getPacketType() == PacketType.Play.Client.CHAT_MESSAGE + || event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND + || event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND_UNSIGNED + ) { + if (isStringTooBig(event)) { + event.setCancelled(true); + onCancel(log, kick, event.getUser()); + } + } + } + + private boolean isStringTooBig(PacketReceiveEvent event) { + int strBufLen = ByteBufHelper.readVarInt(event.getByteBuf()); + + // Check if the received encoded string buffer length is zero or longer than maximum allowed + if (strBufLen < 0 || strBufLen > charLimit * 4) { + return true; + } + + // The received string length is longer than maximum allowed + return ByteBufHelper.toString(event.getByteBuf(), ByteBufHelper.readerIndex(event.getByteBuf()), strBufLen, StandardCharsets.UTF_8) + .length() > charLimit; + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/InventoryLag.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/InventoryLag.java index e1e2bd18d..e8676ff8b 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/InventoryLag.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/InventoryLag.java @@ -34,15 +34,15 @@ public class InventoryLag extends PacketModule implements Listener { - private final Cache playerDataCache; private final Set measuredPacketTypes; - private final long rateLimitBytes, lockoutBytes, lockoutMillis; + private final long playerCacheMillis, rateLimitBytes, lockoutBytes, lockoutMillis; private final int screenOpenLimit, screenOpenDelay; private final boolean closeInventory, log; + private Cache playerDataCache; + public InventoryLag() { - super("patches.inventory-lag", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", """ + super("patches.inventory-lag", false, PacketListenerPriority.HIGHEST, """ Checks if a player is requesting unusual amounts of traffic from the server\s using ItemStacks.\s If a player exceeds the limit, they will be put on a cooldown, during which\s @@ -53,10 +53,9 @@ public InventoryLag() { Whether to immediately close any open inventory of the player on limit exceed\s Note: Closing has to be scheduled so it will take a bit if the server is heavily\s lagging."""); - this.playerDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(Math.max(1L, - config.getLong(configPath + ".byte-data-keep-time-millis", 30_000, """ - The time in millis in which to check if the player exceeded the limit.\s - Needs to be at least as long as your lockout duration millis.""")))).build(); + this.playerCacheMillis = Math.max(1L, config.getLong(configPath + ".byte-data-keep-time-millis", 30_000, """ + The time in millis in which to check if the player exceeded the limit.\s + Needs to be at least as long as your lockout duration millis.""")); this.rateLimitBytes = config.getLong(configPath + ".rate-limit.bytesize-limit", 8_000_000, """ The limit in bytes the server has sent the server in the form of ItemStacks,\s before the player will be put on a rate-limit.\s @@ -88,13 +87,9 @@ public InventoryLag() { .collect(Collectors.toCollection(HashSet::new)); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void enable() { + playerDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(playerCacheMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); PacketEvents.getAPI().getEventManager().registerListener(asAbstract); } @@ -103,6 +98,11 @@ public void enable() { public void disable() { HandlerList.unregisterAll(this); PacketEvents.getAPI().getEventManager().unregisterListener(asAbstract); + if (playerDataCache != null) { + playerDataCache.invalidateAll(); + playerDataCache.cleanUp(); + playerDataCache = null; + } } @Override diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/MapCursorLag.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/MapCursorLag.java index 609406f46..a1d22ec18 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/MapCursorLag.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/MapCursorLag.java @@ -14,29 +14,22 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerInteractEntityEvent; -import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.EntitiesLoadEvent; public class MapCursorLag extends PacketModule implements Listener { public MapCursorLag() { - super("patches.map-cursor-lag-patch", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", """ + super("patches.map-cursor-lag-patch", false, PacketListenerPriority.HIGHEST, """ Patches the famous stacked map cursor lag that causes both\s client and server crashes."""); } @Override public void enable() { - if (EntityUtil.canDisableMapPositionCursor()) - plugin.getServer().getPluginManager().registerEvents(this, plugin); + plugin.getServer().getPluginManager().registerEvents(this, plugin); PacketEvents.getAPI().getEventManager().registerListener(asAbstract); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -52,14 +45,9 @@ public void onPacketSend(PacketSendEvent event) { } } - /* - For 1.16 and up - */ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - private void onChunkLoad(ChunkLoadEvent event) { - if (event.isNewChunk()) return; - - for (Entity entity : event.getChunk().getEntities()) { + private void onEntitiesLoad(EntitiesLoadEvent event) { + for (Entity entity : event.getEntities()) { if (EntityUtil.ITEM_FRAMES.contains(entity.getType())) { EntityUtil.disableMapPositionCursor((ItemFrame) entity); } @@ -68,9 +56,8 @@ private void onChunkLoad(ChunkLoadEvent event) { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) private void onInteract(PlayerInteractEntityEvent event) { - Entity rightClicked = event.getRightClicked(); - if (EntityUtil.ITEM_FRAMES.contains(rightClicked.getType())) { - EntityUtil.disableMapPositionCursor((ItemFrame) rightClicked); + if (EntityUtil.ITEM_FRAMES.contains(event.getRightClicked().getType())) { + EntityUtil.disableMapPositionCursor((ItemFrame) event.getRightClicked()); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/PacketModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/PacketModule.java index cf4275353..d9cf7d734 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/PacketModule.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/PacketModule.java @@ -9,16 +9,19 @@ import me.xginko.aef.utils.models.ExpiringSet; import java.time.Duration; -import java.util.Set; import java.util.UUID; public abstract class PacketModule extends AEFModule implements PacketListener { protected final PacketListenerAbstract asAbstract; - private final Set loggingCooldown; + protected final ExpiringSet loggingCooldown; - public PacketModule(String configPath, PacketListenerPriority priority) { - super(configPath); + public PacketModule(String configPath, boolean enabledByDefault, PacketListenerPriority priority) { + this(configPath, enabledByDefault, priority, null); + } + + public PacketModule(String configPath, boolean enabledByDefault, PacketListenerPriority priority, String comment) { + super(configPath, enabledByDefault, comment); this.asAbstract = asAbstract(priority); // Otherwise will log for each received packet, which would be a LOT this.loggingCooldown = new ExpiringSet<>(Duration.ofMinutes(5)); @@ -35,11 +38,9 @@ public void disable() { } public void onCancel(boolean log, boolean kick, User sender) { - if (log) { - if (!loggingCooldown.contains(sender.getUUID())) { - info(sender.getName() + " failed to trigger exploit."); - loggingCooldown.add(sender.getUUID()); - } + if (log && !loggingCooldown.contains(sender.getUUID())) { + info(sender.getName() + " failed to trigger exploit."); + loggingCooldown.add(sender.getUUID()); } if (kick) { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/PurpurBeehiveCrash.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/PurpurBeehiveCrash.java index 4f6967ee9..37eb55fbd 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/PurpurBeehiveCrash.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/PurpurBeehiveCrash.java @@ -23,8 +23,7 @@ public class PurpurBeehiveCrash extends PacketModule { private final boolean log, kick; public PurpurBeehiveCrash() { - super("patches.beehive-crash-patch", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", """ + super("patches.beehive-crash-patch", PlatformUtil.isPurpur(), PacketListenerPriority.HIGHEST, """ Patches a server crash exploit exclusive to Purpur servers.\s This exploit works due to PurpurClient having a feature that\s lets clients request stored data of a clicked beehive from\s @@ -38,11 +37,6 @@ public PurpurBeehiveCrash() { this.kick = config.getBoolean(configPath + ".kick-player", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", PlatformUtil.isPurpur()); - } - @Override public void onPacketReceive(PacketReceiveEvent event) { if (event.isCancelled() || event.getPlayer() == null) return; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/SequenceCrash.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/SequenceCrash.java index 6a4fe8a49..003316934 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/SequenceCrash.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/SequenceCrash.java @@ -13,8 +13,7 @@ public class SequenceCrash extends PacketModule { private final boolean log, kick; public SequenceCrash() { - super("patches.sequence-crash-patch", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", """ + super("patches.sequence-crash-patch", true, PacketListenerPriority.HIGHEST, """ Patches a variety of lag/crash exploits that involves sending packets\s with invalid sequences."""); this.log = config.getBoolean(configPath + ".log", false); @@ -23,7 +22,7 @@ public SequenceCrash() { @Override public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true) && PlatformUtil.getMinecraftVersion() >= 19; + return configEnabled && PlatformUtil.getMinecraftVersion() >= 19; } @Override diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/SignLag.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/SignLag.java index 8d77c00e6..844990245 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/SignLag.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/SignLag.java @@ -1,5 +1,6 @@ package me.xginko.aef.modules.packets; +import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.event.PacketListenerPriority; import com.github.retrooper.packetevents.event.PacketReceiveEvent; import com.github.retrooper.packetevents.protocol.packettype.PacketType; @@ -11,19 +12,19 @@ public class SignLag extends PacketModule { - private final ExpiringSet cooldowns; + private final long cooldownMillis; private final int line_char_limit, total_char_limit; private final boolean log, kick; + private ExpiringSet cooldowns; + public SignLag() { - super("patches.sign-lag", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", """ + super("patches.sign-lag", true, PacketListenerPriority.HIGHEST, """ Patches a lag exploit that involves sending specific oversized\s sign edit packets."""); - this.cooldowns = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".packet-delay-in-ticks", 10, - "How many ticks a player needs to wait to be able to send\n" + - "another sign update packet (renaming or writing).")) * 50L)); + this.cooldownMillis = Math.max(1, config.getInt(configPath + ".packet-delay-in-ticks", 10, + "How many ticks a player needs to wait to be able to send\n" + + "another sign update packet (renaming or writing).")) * 50L; this.line_char_limit = config.getInt(configPath + ".line-character-limit", 80, "Vanilla limit is 384 characters per line, which can be too much."); this.total_char_limit = config.getInt(configPath + ".total-char-limit", 384, @@ -33,8 +34,19 @@ public SignLag() { } @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); + public void enable() { + cooldowns = new ExpiringSet<>(Duration.ofMillis(cooldownMillis)); + PacketEvents.getAPI().getEventManager().registerListener(asAbstract); + } + + @Override + public void disable() { + PacketEvents.getAPI().getEventManager().unregisterListener(asAbstract); + if (cooldowns != null) { + cooldowns.clear(); + cooldowns.cleanUp(); + cooldowns = null; + } } @Override @@ -42,8 +54,12 @@ public void onPacketReceive(PacketReceiveEvent event) { if (event.isCancelled()) return; if (event.getPacketType() != PacketType.Play.Client.UPDATE_SIGN) return; - if (cooldowns.contains(event.getUser().getUUID())) return; - cooldowns.add(event.getUser().getUUID()); + if (cooldowns.contains(event.getUser().getUUID())) { + event.setCancelled(true); + return; + } else { + cooldowns.add(event.getUser().getUUID()); + } int sum = 0; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/TabCompleteCrash.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/TabCompleteCrash.java index 399e7773f..03c5d9e85 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/TabCompleteCrash.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/TabCompleteCrash.java @@ -6,24 +6,21 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientTabComplete; import org.bukkit.permissions.ServerOperator; +import java.util.List; + public class TabCompleteCrash extends PacketModule { - private static final String[] ABUSABLE_SEQUENCES = { "@", "[", "nbt", "=", "{", "}", "]" }; + private final String[] sequences; private final boolean log, kick; public TabCompleteCrash() { - super("patches.tab-complete-crash-patch", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", """ + super("patches.tab-complete-crash-patch", true, PacketListenerPriority.HIGHEST, """ Patches two lag exploits and an instant server shutdown exploit that\s works by sending a malicious TabComplete packet that triggers a\s StackOverflowError inside the TagParser class."""); this.log = config.getBoolean(configPath + ".log", false); this.kick = config.getBoolean(configPath + ".kick-player", false); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); + this.sequences = config.getList(configPath + ".characters", List.of("@", "[", "nbt", "=", "{", "}", "]")).toArray(new String[0]); } @Override @@ -51,8 +48,8 @@ public void onPacketReceive(PacketReceiveEvent event) { if (event.getPlayer() == null || ((ServerOperator) event.getPlayer()).isOp()) return; - for (String sequence : ABUSABLE_SEQUENCES) { - if (text.indexOf(sequence) != -1) { + for (String sequence : sequences) { + if (text.contains(sequence)) { event.setCancelled(true); onCancel(log, kick, event.getUser()); return; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/WindowClickCrash.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/WindowClickCrash.java index e33595b7b..bae3e3b35 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/WindowClickCrash.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/packets/WindowClickCrash.java @@ -11,8 +11,7 @@ public class WindowClickCrash extends PacketModule { private final boolean log, kick; public WindowClickCrash() { - super("patches.window-click-crash-patch", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", """ + super("patches.window-click-crash-patch", true, PacketListenerPriority.HIGHEST, """ Patches a variety of different lag and crash methods that work\s by sending invalid Window Click packets, causing the server to\s dump error logs until it runs out of memory."""); @@ -20,15 +19,11 @@ public WindowClickCrash() { this.kick = config.getBoolean(configPath + ".kick-player", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void onPacketReceive(PacketReceiveEvent event) { if (event.isCancelled()) return; if (event.getPacketType() != PacketType.Play.Client.CLICK_WINDOW) return; + WrapperPlayClientClickWindow packet = new WrapperPlayClientClickWindow(event); int button = packet.getButton(); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/GodMode.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/GodMode.java index 3d4b0d14a..55a7e7da4 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/GodMode.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/GodMode.java @@ -15,8 +15,7 @@ public class GodMode extends AEFModule implements Listener { public GodMode() { - super("patches.experimental-godmode-patch"); - config.addComment(configPath, """ + super("patches.experimental-godmode-patch", false, """ Removes entities or players if they are invalid, dead or not located within a ticking chunk. Not sure if this works."""); } @@ -26,11 +25,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/BookBan.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/ItemDataBan.java similarity index 78% rename from AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/BookBan.java rename to AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/ItemDataBan.java index 49d0197ca..225d1b9fe 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/BookBan.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/ItemDataBan.java @@ -24,14 +24,19 @@ import java.time.Duration; import java.util.UUID; -public class BookBan extends AEFModule implements Listener { +public class ItemDataBan extends AEFModule implements Listener { - private final Cache cachedItemSizes, cachedInventorySizes; + private final long itemSizeCacheMillis, inventorySizeCacheMillis; private final int maxBookSize, maxItemSize, maxInventorySize, maxAuthorChars, maxTitleChars, maxPages; private final boolean useUTF16, kickOnBigBook; - public BookBan() { - super("patches.anti-book-ban"); + private Cache cachedItemSizes, cachedInventorySizes; + + public ItemDataBan() { + super("patches.anti-item-ban", false, """ + More commonly known as book-ban:\s + Prevents player's getting banned from items with big nbt/compound data.\s + This check applies to all item data, not just books."""); this.useUTF16 = config.getBoolean(configPath + ".use-UTF-16", false, """ If set to false, will use UTF-8.\s Charset to use to encode the result of NBTCompound#toString into\s @@ -41,36 +46,39 @@ public BookBan() { this.maxBookSize = config.getInt(configPath + ".max-book-size", 56000); this.kickOnBigBook = config.getBoolean(configPath + ".kick-on-too-large-book-edit", true, "Kicks players when they try to create a book bigger than the limit."); - this.maxAuthorChars = config.getInt(configPath + ".max-author-chars", 32); - this.maxTitleChars = config.getInt(configPath + ".max-title-chars", 32); + this.maxAuthorChars = config.getInt(configPath + ".max-author-chars", 30); + this.maxTitleChars = config.getInt(configPath + ".max-title-chars", 30); this.maxPages = config.getInt(configPath + ".max-pages", 100); this.maxItemSize = config.getInt(configPath + ".max-item-size", 56000); this.maxInventorySize = config.getInt(configPath + ".max-inventory-size", 2050000); - this.cachedItemSizes = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".dropped-items-size-cache-ticks", 120, """ - How long in ticks a dropped item's size should be cached after\s - checking.""")) * 50L - )).build(); - this.cachedInventorySizes = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".player-inventory-size-cache-ticks", 20, """ - How long in ticks a player's inventory size should be cached after\s - checking.""")) * 50L - )).build(); + this.itemSizeCacheMillis = Math.max(1,config.getInt(configPath + ".dropped-items-size-cache-ticks", 120, """ + How long in ticks a dropped item's size should be cached after\s + checking.""")) * 50L; + this.inventorySizeCacheMillis = Math.max(1, config.getInt(configPath + ".player-inventory-size-cache-ticks", 20, """ + How long in ticks a player's inventory size should be cached after\s + checking.""")) * 50L; } @Override public void enable() { + cachedItemSizes = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(itemSizeCacheMillis)).build(); + cachedInventorySizes = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(inventorySizeCacheMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (cachedItemSizes != null) { + cachedItemSizes.invalidateAll(); + cachedItemSizes.cleanUp(); + cachedItemSizes = null; + } + if (cachedInventorySizes != null) { + cachedInventorySizes.invalidateAll(); + cachedInventorySizes.cleanUp(); + cachedInventorySizes = null; + } } @SuppressWarnings("DataFlowIssue") // Legitimate because we make sure no values are null by testing .hasX() diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/PearlPhase.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/PearlPhase.java deleted file mode 100644 index 1c65dd580..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/PearlPhase.java +++ /dev/null @@ -1,141 +0,0 @@ -package me.xginko.aef.modules.patches; - -import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.LocationUtil; -import me.xginko.aef.utils.MaterialUtil; -import me.xginko.aef.utils.PlatformUtil; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerTeleportEvent; - -import java.util.EnumSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class PearlPhase extends AEFModule implements Listener { - - private final Set glitchyMaterial; - private final double maxDistance; - private final int radius; - private long schedulingTimeoutMillis; - - public PearlPhase() { - super("patches.pearl-phase"); - config.addComment(configPath+ ".enable", - "Attempts to patch a pearl phasing exploit by cancelling the teleport\n" + - "if the pearl is thrown at or near a specific block.\n" + - "At the time of the creation of this module, this is an issue with NoCheatPlus."); - this.radius = Math.min(1, config.getInt(configPath + ".search-radius", 2, - "How many blocks around the teleport location should be searched\n" + - "for potential glitch blocks if the teleport location isn't one itself.")); - this.maxDistance = config.getDouble(configPath + ".maximum-distance-to-cancel-teleport", 3.0); - - Stream concatA = Stream.concat(MaterialUtil.SLAB_LIKE.stream(), - Stream.of(XMaterial.COBWEB, XMaterial.POWDER_SNOW).filter(XMaterial::isSupported).map(XMaterial::parseMaterial)); - Stream concatB = Stream.concat(MaterialUtil.PRESSURE_PLATES.stream(), MaterialUtil.TRAPDOORS.stream()); - List defaults = Stream.concat(concatA, concatB) - .map(Enum::name) - .sorted() - .toList(); - this.glitchyMaterial = config.getList(configPath+".glitchy-materials", defaults) - .stream() - .map(configuredType -> { - try { - return Material.valueOf(configuredType); - } catch (IllegalArgumentException e) { - notRecognized(Material.class, configuredType); - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); - if (PlatformUtil.isFolia()) { - this.schedulingTimeoutMillis = config.getInt(configPath + ".check-timeout-millis", 800, - "We will have to schedule the check on folia, meaning theres a chance\n" + - "the task might take longer than expected. To make sure that does not cause\n" + - "more lag, we set a time limit here."); - } - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath+".enable", false); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPlayerTeleport(PlayerTeleportEvent event) { - if (event.getCause() != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) return; - - Location destination = event.getTo(); - if (LocationUtil.getRelDistance2D(event.getFrom(), destination) >= maxDistance) return; - - if (!PlatformUtil.isFolia()) { - if (isPotentialPhase(destination)) - event.setCancelled(true); - return; - } - - try { - CompletableFuture future = new CompletableFuture<>(); - // We will have to schedule the check on folia because the event might not - // fire from the same thread as the region of the destination location. - plugin.getServer().getRegionScheduler().execute(plugin, destination, () -> - future.complete(isPotentialPhase(destination))); - if (future.get(schedulingTimeoutMillis, TimeUnit.MILLISECONDS)) - event.setCancelled(true); - } catch (ExecutionException | InterruptedException | TimeoutException e) { - error("Error while checking if the destination would trigger phasing.", e); - } - } - - private boolean isPotentialPhase(Location location) { - Block destBlock = location.getBlock(); - - if (glitchyMaterial.contains(destBlock.getType())) { - return true; - } - - int centerX = destBlock.getX(); - int centerY = destBlock.getY(); - int centerZ = destBlock.getZ(); - World world = destBlock.getWorld(); - - for (int x = centerX - radius; x <= centerX + radius; x++) { - for (int z = centerZ - radius; z <= centerZ + radius; z++) { - for (int y = Math.max(world.getMinHeight(), centerY - radius); y <= centerY + radius; y++) { - if (y > world.getMaxHeight()) break; - - if (glitchyMaterial.contains(world.getBlockAt(x, y, z).getType())) { - return true; - } - } - } - } - - return false; - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/TeleportCoordExploit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/TeleportCoordExploit.java index fd2da8d79..1c32c98d5 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/TeleportCoordExploit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/TeleportCoordExploit.java @@ -18,8 +18,7 @@ public class TeleportCoordExploit extends AEFModule implements Listener { private final int minDistanceToVanishPlayers; public TeleportCoordExploit() { - super("patches.prevent-teleport-coordinate-exploit"); - config.addComment(configPath + ".enable", """ + super("patches.prevent-teleport-coordinate-exploit", true, """ Patches coordinate exploit for teleportation commands such as /tpa, /home AS WELL as respawn exploits.\s This is done by vanishing the player for x ticks before teleporting."""); @@ -32,11 +31,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -57,7 +51,7 @@ private void tempVanish(Player player) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onTeleport(PlayerTeleportEvent event) { switch (event.getCause()) { - case ENDER_PEARL, COMMAND, PLUGIN -> { + case ENDER_PEARL, COMMAND, PLUGIN, UNKNOWN, SPECTATE -> { if (LocationUtil.getRelDistance2D(event.getFrom(), event.getTo()) >= minDistanceToVanishPlayers) { this.tempVanish(event.getPlayer()); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/WorldChangeCrash.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/WorldChangeCrash.java index db5d2fd3a..0a220b21f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/WorldChangeCrash.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/WorldChangeCrash.java @@ -14,34 +14,35 @@ public class WorldChangeCrash extends AEFModule implements Listener { - private final ExpiringSet recentWorldChangers; + private final long worldChangeDelayMillis; private final boolean shouldLog; + private ExpiringSet recentWorldChangers; + public WorldChangeCrash() { - super("patches.prevent-fast-world-teleport-crash"); - config.addComment(configPath + ".enable", """ + super("patches.prevent-fast-world-teleport-crash", false, """ Prevents crash methods that involve very fast teleporting between\s different worlds in a short time."""); - this.recentWorldChangers = new ExpiringSet<>(Duration.ofMillis( - Math.max(1, config.getInt(configPath + ".teleport-delay-millis", 1000, """ - Time in milliseconds until an entity can teleport to another\s - world again.""")))); + this.worldChangeDelayMillis = Math.max(1, config.getInt(configPath + ".teleport-delay-millis", 1000, """ + Time in milliseconds until an entity can teleport to another\s + world again.""")); this.shouldLog = config.getBoolean(configPath + ".log", false); } @Override public void enable() { + recentWorldChangers = new ExpiringSet<>(Duration.ofMillis(worldChangeDelayMillis)); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (recentWorldChangers != null) { + recentWorldChangers.clear(); + recentWorldChangers.cleanUp(); + recentWorldChangers = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/commandsign/CommandSign.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/commandsign/CommandSign.java index 4621b5a6c..6aadc140f 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/commandsign/CommandSign.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/patches/commandsign/CommandSign.java @@ -9,8 +9,7 @@ public class CommandSign extends AEFModule { private final Listener signCommandListener; public CommandSign() { - super("patches.prevent-command-sign"); - config.addComment(configPath + ".enable", """ + super("patches.prevent-command-sign", true, """ Patch signs that have run_command NBT tags attached, allowing the\s to run a command with operator permissions on click.\s Recommended to enable if you had a rogue admin or backdoor incident."""); @@ -22,11 +21,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(signCommandListener, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(signCommandListener); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/BedTrap.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/BedTrap.java deleted file mode 100755 index 549081e34..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/BedTrap.java +++ /dev/null @@ -1,90 +0,0 @@ -package me.xginko.aef.modules.preventions; - -import com.destroystokyo.paper.event.player.PlayerPostRespawnEvent; -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; -import me.xginko.aef.events.PacketPlayerRespawnEvent; -import me.xginko.aef.modules.AEFModule; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; - -import java.time.Duration; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; - -public class BedTrap extends AEFModule implements Listener { - - private final Cache playerDeathNearBedCount; - private final int maxDeathsPerTime; - private final boolean shouldLog; - - public BedTrap() { - super("preventions.anti-bed-trap"); - config.addComment(configPath + ".enable", """ - Resets a players bed respawn they die too many times within\s - a certain timeframe."""); - this.maxDeathsPerTime = config.getInt(configPath + ".max-deaths-per-time", 7, """ - Amount of times player can die until he is determined as bed-trapped."""); - this.playerDeathNearBedCount = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(Math.max(1, - config.getInt(configPath + ".time-in-seconds", 5, """ - "Time until death counter will be reset again.""")))).build(); - this.shouldLog = config.getBoolean(configPath+".log", false); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @SuppressWarnings("deprecation") - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPlayerPostRespawn(PlayerPostRespawnEvent event) { - Player player = event.getPlayer(); - if (!event.isBedSpawn()) return; - - if (playerDeathNearBedCount.get(player.getUniqueId(), k -> new AtomicInteger()).incrementAndGet() <= maxDeathsPerTime) { - return; - } - - player.getScheduler().execute(plugin, () -> { - try { - player.setRespawnLocation(null, true); - } catch (NoSuchMethodError e) { - player.setBedSpawnLocation(null, true); - } - if (shouldLog) info("Reset bed respawn of potentially bed-trapped player '" + player.getName() + "'"); - }, null, 1L); - } - - @SuppressWarnings("deprecation") - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPacketPlayerRespawn(PacketPlayerRespawnEvent event) { - Player player = event.getPlayer(); - if (!event.isPotentialBedSpawn()) return; - - if (playerDeathNearBedCount.get(player.getUniqueId(), k -> new AtomicInteger()).incrementAndGet() <= maxDeathsPerTime) { - return; - } - - try { - player.setRespawnLocation(null, true); - } catch (NoSuchMethodError e) { - player.setBedSpawnLocation(null, true); - } - - if (shouldLog) info("Reset bed respawn of potentially bed-trapped player '" + player.getName() + "'"); - } -} \ No newline at end of file diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/IllegalGameMode.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/IllegalGameMode.java new file mode 100755 index 000000000..c8617feb8 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/IllegalGameMode.java @@ -0,0 +1,115 @@ +package me.xginko.aef.modules.preventions; + +import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import io.papermc.paper.event.player.AsyncChatEvent; +import me.xginko.aef.modules.AEFModule; +import org.bukkit.GameMode; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class IllegalGameMode extends AEFModule implements Listener { + + private final Map worldSettings; + private final Set allowedGamemodePlayers; + private final GameMode defaultGamemode; + private final boolean shouldLog; + + public IllegalGameMode() { + super("preventions.illegal-gamemode", false, """ + Forces GameMode for players not in the whitelist.\s + Useful protection against past and future backdoor incidents"""); + this.shouldLog = config.getBoolean(configPath+".log", true); + + GameMode gameMode; + String configuredGamemode = config.getString(configPath + ".default-gamemode", GameMode.SURVIVAL.name(), + "GameModes: " + Arrays.stream(GameMode.values()).map(Enum::name).collect(Collectors.joining(", "))); + try { + gameMode = GameMode.valueOf(configuredGamemode); + } catch (IllegalArgumentException e) { + notRecognized(GameMode.class, configuredGamemode); + gameMode = GameMode.SURVIVAL; + } + this.defaultGamemode = gameMode; + + Map defaults = new HashMap<>(3); + defaults.put("world", GameMode.SURVIVAL.name()); + defaults.put("world_nether", GameMode.SURVIVAL.name()); + defaults.put("world_the_end", GameMode.SURVIVAL.name()); + + ConfigSection section = config.getConfigSection(configPath + ".world-gamemodes", defaults); + List worlds = section.getKeys(false); + this.worldSettings = new HashMap<>(worlds.size()); + for (String world : worlds) { + try { + worldSettings.put(world, GameMode.valueOf(section.getString(world))); + } catch (IllegalArgumentException e) { + notRecognized(GameMode.class, world); + } + } + + this.allowedGamemodePlayers = new HashSet<>(config.getList(configPath + ".whitelisted-players", + List.of("Notch"))); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + private void checkForIllegalGameMode(HumanEntity player) { + if (allowedGamemodePlayers.contains(player.getName())) return; + + GameMode targetGamemode = worldSettings.getOrDefault(player.getWorld().getName(), defaultGamemode); + + if (player.getGameMode() != targetGamemode) { + if (shouldLog) warn(player.getName() + " is GameMode " + player.getGameMode().name() + + " in world " + player.getWorld().getName() + ". Setting to " + targetGamemode.name()); + player.setGameMode(targetGamemode); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onInventory(InventoryEvent event) { + checkForIllegalGameMode(event.getView().getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onJoin(PlayerJoinEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onMove(PlayerMoveEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST) + private void onChat(AsyncChatEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST) + private void onCommand(PlayerCommandPreprocessEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/PreventOppedPlayers.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/IllegalPermissions.java similarity index 59% rename from AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/PreventOppedPlayers.java rename to AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/IllegalPermissions.java index 3cb3ac6ef..4a0d0a76c 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/PreventOppedPlayers.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/IllegalPermissions.java @@ -1,7 +1,9 @@ package me.xginko.aef.modules.preventions; import io.papermc.paper.event.player.AsyncChatEvent; +import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.enums.TriState; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -16,16 +18,18 @@ import java.util.List; import java.util.Set; -public class PreventOppedPlayers extends AEFModule implements Listener { +public class IllegalPermissions extends AEFModule implements Listener { - private final Set allowedOperators; + private final Set allowedOperators, blacklistedPermissions; private final boolean shouldLog; - public PreventOppedPlayers() { - super("preventions.prevent-opped-players"); - config.addComment(configPath + ".enable", "Useful if you suspect a backdoor has happened."); - this.shouldLog = config.getBoolean(configPath+".log", false); + public IllegalPermissions() { + super("preventions.illegal-permissions", false, """ + Strips/prevents certain permissions being used by unauthorized players. + Useful protection against past and future backdoor incidents"""); + this.shouldLog = config.getBoolean(configPath+".log", true); this.allowedOperators = new HashSet<>(config.getList(configPath + ".whitelisted-players", List.of("Notch"))); + this.blacklistedPermissions = new HashSet<>(config.getList(configPath + ".blacklisted-permissions", List.of("*"))); } @Override @@ -33,11 +37,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -46,9 +45,16 @@ public void disable() { private void checkForIllegalOp(Player player) { if (allowedOperators.contains(player.getName())) return; - if (player.isOp() || player.hasPermission("*")) { + if (player.isOp()) { + if (shouldLog) warn(player.getName() + " is not in the operators whitelist. Removing operator status."); player.setOp(false); - if (shouldLog) warn("Deopped illegally opped player '"+player.getName()+"'."); + } + + for (String permission : blacklistedPermissions) { + if (AnarchyExploitFixes.permissions().permissionValue(player, permission) == TriState.TRUE) { + if (shouldLog) warn(player.getName() + " was found with an illegal permission: '" + permission + "'. Setting it explicitly FALSE."); + AnarchyExploitFixes.permissions().setPermission(player, permission, TriState.FALSE); + } } } @@ -72,7 +78,7 @@ private void onChat(AsyncChatEvent event) { checkForIllegalOp(event.getPlayer()); } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.LOWEST) // Ensure this runs first private void onCommand(PlayerCommandPreprocessEvent event) { checkForIllegalOp(event.getPlayer()); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/NetherRoof.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/NetherRoof.java index 685d73503..73d0a673d 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/NetherRoof.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/NetherRoof.java @@ -3,17 +3,14 @@ import com.cryptomorin.xseries.XEntityType; import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.LocationUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.entity.Vehicle; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; @@ -29,8 +26,8 @@ public class NetherRoof extends AEFModule implements Listener { private final boolean safe_teleport_enabled; public NetherRoof() { - super("preventions.prevent-nether-roof"); - config.addComment(configPath + ".enable", "Prevent players from going above the nether roof."); + super("preventions.prevent-nether-roof", true, + "Prevent players from going above the nether roof."); this.safe_teleport_enabled = config.getBoolean(configPath + ".safely-teleport-players", true); } @@ -39,11 +36,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -53,7 +45,7 @@ public void disable() { private void onTeleport(PlayerTeleportEvent event) { if ( LocationUtil.isNetherCeiling(event.getTo()) - && !CachingPermTool.hasPermission(AEFPermission.BYPASS_NETHER_ROOF, event.getPlayer()) + && !AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), AEFPermission.BYPASS_NETHER_ROOF.node()).toBoolean() ) { event.setCancelled(true); } @@ -61,12 +53,11 @@ private void onTeleport(PlayerTeleportEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { - final Player player = event.getPlayer(); if ( - LocationUtil.isNetherCeiling(player.getLocation()) - && !CachingPermTool.hasPermission(AEFPermission.BYPASS_NETHER_ROOF, player) + LocationUtil.isNetherCeiling(event.getPlayer().getLocation()) + && !AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), AEFPermission.BYPASS_NETHER_ROOF.node()).toBoolean() ) { - Location belowCeiling = getBelowCeilLocation(player.getLocation()); + Location belowCeiling = getBelowCeilLocation(event.getPlayer().getLocation()); event.setTo(belowCeiling); createSafespace(belowCeiling); } @@ -74,15 +65,14 @@ private void onPlayerMove(PlayerMoveEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onVehicleMove(VehicleMoveEvent event) { - final Vehicle vehicle = event.getVehicle(); - if (!LocationUtil.isNetherCeiling(vehicle.getLocation())) return; + if (!LocationUtil.isNetherCeiling(event.getVehicle().getLocation())) return; - for (Entity passenger : vehicle.getPassengers()) { + for (Entity passenger : event.getVehicle().getPassengers()) { if (passenger.getType() == XEntityType.PLAYER.get() - && CachingPermTool.hasPermission(AEFPermission.BYPASS_NETHER_ROOF, (Player) passenger)) return; + && AnarchyExploitFixes.permissions().permissionValue(passenger, AEFPermission.BYPASS_NETHER_ROOF.node()).toBoolean()) return; } - for (Entity passenger : vehicle.getPassengers()) { + for (Entity passenger : event.getVehicle().getPassengers()) { if (passenger.getType() == XEntityType.PLAYER.get()) { teleportFromCeiling((Player) passenger); } else { @@ -91,20 +81,19 @@ private void onVehicleMove(VehicleMoveEvent event) { } } - vehicle.remove(); + event.getVehicle().remove(); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPlace(BlockPlaceEvent event) { - final Player player = event.getPlayer(); - if (CachingPermTool.hasPermission(AEFPermission.BYPASS_NETHER_ROOF, player)) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), AEFPermission.BYPASS_NETHER_ROOF.node()).toBoolean()) return; if (LocationUtil.isNetherCeiling(event.getBlock().getLocation())) { event.setCancelled(true); } - if (LocationUtil.isNetherCeiling(player.getLocation())) { - teleportFromCeiling(player); + if (LocationUtil.isNetherCeiling(event.getPlayer().getLocation())) { + teleportFromCeiling(event.getPlayer()); } } @@ -128,34 +117,34 @@ private void createSafespace(Location location) { plugin.getServer().getRegionScheduler().execute(plugin, location, () -> { // Check block above for liquid or falling block Block blockAboveHead = location.clone().add(0, 2, 0).getBlock(); - if (isUnsafe(blockAboveHead) && blockAboveHead.getType() != XMaterial.NETHER_PORTAL.parseMaterial()) - blockAboveHead.setType(XMaterial.NETHERRACK.parseMaterial(), false); + if (isUnsafe(blockAboveHead) && blockAboveHead.getType() != XMaterial.NETHER_PORTAL.get()) + blockAboveHead.setType(XMaterial.NETHERRACK.get(), false); // Create an air pocket for the player Block blockAtPlayerLegs = location.getBlock(); - if (blockAtPlayerLegs.getType() != Material.AIR && blockAtPlayerLegs.getType() != XMaterial.NETHER_PORTAL.parseMaterial()) - blockAtPlayerLegs.setType(Material.AIR, false); + if (!blockAtPlayerLegs.getType().isAir() && blockAtPlayerLegs.getType() != XMaterial.NETHER_PORTAL.get()) + blockAtPlayerLegs.setType(XMaterial.AIR.get(), false); Block blockAtPlayerTorso = blockAtPlayerLegs.getRelative(BlockFace.UP); - if (blockAtPlayerTorso.getType() != Material.AIR && blockAtPlayerTorso.getType() != XMaterial.NETHER_PORTAL.parseMaterial()) - blockAtPlayerTorso.setType(Material.AIR, false); + if (!blockAtPlayerTorso.getType().isAir() && blockAtPlayerTorso.getType() != XMaterial.NETHER_PORTAL.get()) + blockAtPlayerTorso.setType(XMaterial.AIR.get(), false); // Check all sides of air pocket for liquids and fill with netherrack for (int i = 0; i < 2; i++) { Block airPocketBlock = blockAtPlayerLegs.getRelative(BlockFace.UP, i); for (BlockFace face : CARDINAL_FACES) { Block around = airPocketBlock.getRelative(face); - if (isUnsafe(around)) around.setType(XMaterial.NETHERRACK.parseMaterial(), false); + if (isUnsafe(around)) around.setType(XMaterial.NETHERRACK.get(), false); } } // Create block below feet if not solid Block blockBelowFeet = blockAtPlayerLegs.getRelative(BlockFace.DOWN); - if (isUnsafe(blockBelowFeet) || blockBelowFeet.getType() == XMaterial.NETHER_PORTAL.parseMaterial()) - blockBelowFeet.setType(XMaterial.NETHERRACK.parseMaterial(), true); + if (isUnsafe(blockBelowFeet) || blockBelowFeet.getType() == XMaterial.NETHER_PORTAL.get()) + blockBelowFeet.setType(XMaterial.NETHERRACK.get(), true); }); } private static boolean isUnsafe(Block block) { - return block.isLiquid() || block.getType().hasGravity() || !block.getType().isSolid(); + return block.isLiquid() || block.getType().hasGravity() || !block.isSolid(); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/PreventNonSurvival.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/PreventNonSurvival.java deleted file mode 100755 index caf08aeb0..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/PreventNonSurvival.java +++ /dev/null @@ -1,83 +0,0 @@ -package me.xginko.aef.modules.preventions; - -import io.papermc.paper.event.player.AsyncChatEvent; -import me.xginko.aef.modules.AEFModule; -import org.bukkit.GameMode; -import org.bukkit.entity.HumanEntity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerMoveEvent; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class PreventNonSurvival extends AEFModule implements Listener { - - private final Set allowedGamemodePlayers; - private final boolean shouldLog; - - public PreventNonSurvival() { - super("preventions.prevent-non-survival-players"); - config.addComment(configPath + ".enable", """ - Checks if player is in survival and if not, puts him back into survival.\s - Useful if you had a backdoor incident."""); - this.shouldLog = config.getBoolean(configPath+".log", false); - this.allowedGamemodePlayers = new HashSet<>(config.getList(configPath + ".whitelisted-players", - List.of("Notch"))); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - private void checkForIllegalGamemode(HumanEntity player) { - if (allowedGamemodePlayers.contains(player.getName())) return; - - if (player.getGameMode() != GameMode.SURVIVAL) { - player.setGameMode(GameMode.SURVIVAL); - if (shouldLog) warn("Changed gamemode of '"+player.getName()+"' back to survival."); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onInventory(InventoryEvent event) { - checkForIllegalGamemode(event.getView().getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onJoin(PlayerJoinEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onMove(PlayerMoveEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST) - private void onChat(AsyncChatEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST) - private void onCommand(PlayerCommandPreprocessEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonExplodePermBlockRemoval.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonExplodePermBlockRemoval.java index 1f70fe0d3..d8a2d83a2 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonExplodePermBlockRemoval.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonExplodePermBlockRemoval.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.preventions.blockbreak; +import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.MaterialUtil; -import org.bukkit.Material; import org.bukkit.block.BlockFace; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -19,7 +19,7 @@ public class PistonExplodePermBlockRemoval extends AEFModule implements Listener private final Set whitelistedWorlds; public PistonExplodePermBlockRemoval() { - super("preventions.permanent-block-breaking.by-exploding-pistons"); + super("preventions.permanent-block-breaking.by-exploding-pistons", true); this.whitelistedWorlds = new HashSet<>(config.getList(configPath + ".whitelisted-worlds", List.of("example_world_name"))); config.getBoolean(configPath + ".only-for-portals-and-gateways", false, "If enabled, will only protect portals and end gateways"); @@ -30,11 +30,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -52,7 +47,7 @@ private void onEntityExplode(EntityExplodeEvent event) { if (MaterialUtil.INDESTRUCTIBLES.contains(block.getRelative(face).getType())) { // Schedule remove task for each piston location to ensure we are always on the correct thread plugin.getServer().getRegionScheduler().runDelayed(plugin, block.getLocation(), remove -> - block.setType(Material.AIR), 5); + block.setType(XMaterial.AIR.get()), 5); return true; // Remove piston from the list of blocks to be affected by the explosion } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonPlaceWhileRetractPermBlockRemoval.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonPlaceWhileRetractPermBlockRemoval.java index e33586bf4..60e11aa98 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonPlaceWhileRetractPermBlockRemoval.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonPlaceWhileRetractPermBlockRemoval.java @@ -17,7 +17,7 @@ public class PistonPlaceWhileRetractPermBlockRemoval extends AEFModule implement private final Set whitelistedWorlds; public PistonPlaceWhileRetractPermBlockRemoval() { - super("preventions.permanent-block-breaking.by-placing-piston-on-retract"); + super("preventions.permanent-block-breaking.by-placing-piston-on-retract", true); this.whitelistedWorlds = new HashSet<>(config.getList(configPath + ".whitelisted-worlds", List.of("example_world_name"))); } @@ -27,11 +27,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/StructureGrowPermBlockRemoval.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/StructureGrowPermBlockRemoval.java index b67e207be..a10e4dc97 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/StructureGrowPermBlockRemoval.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/blockbreak/StructureGrowPermBlockRemoval.java @@ -14,8 +14,7 @@ public class StructureGrowPermBlockRemoval extends AEFModule implements Listener { public StructureGrowPermBlockRemoval() { - super("preventions.permanent-block-breaking.by-growing-structures"); - config.addComment(configPath + ".enable", """ + super("preventions.permanent-block-breaking.by-growing-structures", true, """ Prevents removal of permanent blocks by growing structures\s like mushrooms into them."""); } @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/EndPortalDestruction.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/EndPortalDestruction.java index f20fa5232..e0060173d 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/EndPortalDestruction.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/EndPortalDestruction.java @@ -32,7 +32,7 @@ public class EndPortalDestruction extends AEFModule implements Listener { private final boolean shouldLog; public EndPortalDestruction() { - super("preventions.portals.prevent-destroying-end-portals"); + super("preventions.portals.prevent-destroying-end-portals", true); this.shouldLog = config.getBoolean(configPath + ".show-logs", true); this.endBedrockProtectRadius = config.getInt(configPath + ".end.bedrock-protection-radius-blocks", 8); this.pillars = config.getList(configPath + ".end.pillar-blocks", @@ -68,11 +68,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -88,14 +83,14 @@ private void onBlockDispense(BlockDispenseEvent event) { private boolean isNearEndPortal(Block dispenser) { for (BlockFace face : BlockFace.values()) { - if (dispenser.getRelative(face).getType() == XMaterial.END_PORTAL.parseMaterial()) return true; + if (dispenser.getRelative(face).getType() == XMaterial.END_PORTAL.get()) return true; } return false; } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerBucketEvent(PlayerBucketEmptyEvent event) { - if (event.getBlockClicked().getRelative(event.getBlockFace()).getType() == XMaterial.END_PORTAL.parseMaterial()) { + if (event.getBlockClicked().getRelative(event.getBlockFace()).getType() == XMaterial.END_PORTAL.get()) { event.setCancelled(true); if (shouldLog) info("Prevented "+event.getPlayer().getName()+" from destroying an end portal using a bucket!"); } @@ -145,7 +140,7 @@ private void onPistonExplode(EntityExplodeEvent event) { || isWithinEndProtectedRadius(block.getLocation()) ) { plugin.getServer().getRegionScheduler().runDelayed(plugin, block.getLocation(), - removePiston -> block.setType(Material.AIR), 5); + removePiston -> block.setType(XMaterial.AIR.get()), 5); return true; } } @@ -160,6 +155,6 @@ private boolean isWithinEndProtectedRadius(Location location) { } private boolean isEndPortal(Material material) { - return material == XMaterial.END_PORTAL_FRAME.parseMaterial() || material == XMaterial.END_PORTAL.parseMaterial(); + return material == XMaterial.END_PORTAL_FRAME.get() || material == XMaterial.END_PORTAL.get(); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventAllEntitiesInPortals.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventAllEntitiesInPortals.java index 0eaba2ead..7ff03aaf6 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventAllEntitiesInPortals.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventAllEntitiesInPortals.java @@ -13,8 +13,7 @@ public class PreventAllEntitiesInPortals extends AEFModule implements Listener { public PreventAllEntitiesInPortals() { - super("preventions.portals.prevent-all-entities-in-portals"); - config.addComment(configPath, """ + super("preventions.portals.prevent-all-entities-in-portals", false, """ Only enable if you must. Does not affect players. CAUTION: Will kill the entity on folia due to broken portal event."""); } @@ -24,11 +23,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventPortalTraps.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventPortalTraps.java index d993a11ce..959f9e39b 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventPortalTraps.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventPortalTraps.java @@ -25,8 +25,7 @@ public class PreventPortalTraps extends AEFModule implements Listener { private final long tpBackDelayTicks; public PreventPortalTraps() { - super("preventions.portals.prevent-portal-traps"); - config.addComment(configPath + ".enable", """ + super("preventions.portals.prevent-portal-traps", false, """ Teleports a player back to the original location if they have been\s standing in a portal for too long."""); int tpBackDelaySeconds = Math.max(1, config.getInt(configPath + ".wait-time-until-tp-back-in-seconds", 10)); @@ -43,11 +42,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -57,10 +51,10 @@ public void disable() { private void onPortalUse(PlayerPortalEvent event) { // Does not fire on folia due to broken API final Player player = event.getPlayer(); player.getScheduler().execute(plugin, () -> { - if (player.getLocation().getBlock().getType() == XMaterial.NETHER_PORTAL.parseMaterial()) { + if (player.getLocation().getBlock().getType() == XMaterial.NETHER_PORTAL.get()) { player.teleportAsync(event.getFrom()).thenAccept(tpHappened -> { if (tpHappened) { - player.playSound(player.getLocation(), XSound.BLOCK_PORTAL_TRAVEL.parseSound(), 1.0F, 1.0F); + player.playSound(player.getLocation(), XSound.BLOCK_PORTAL_TRAVEL.get(), 1.0F, 1.0F); } }); } @@ -80,10 +74,10 @@ private void onPortalEnter(EntityPortalEnterEvent event) { // Only portal event portalEnterLocations.put(player.getUniqueId(), from); player.getScheduler().execute(plugin, () -> { - if (player.getLocation().getBlock().getType() == XMaterial.NETHER_PORTAL.parseMaterial()) { + if (player.getLocation().getBlock().getType() == XMaterial.NETHER_PORTAL.get()) { player.teleportAsync(from).thenAccept(tpHappened -> { if (tpHappened) { - player.playSound(player.getLocation(), XSound.BLOCK_PORTAL_TRAVEL.parseSound(), 1.0F, 1.0F); + player.playSound(player.getLocation(), XSound.BLOCK_PORTAL_TRAVEL.get(), 1.0F, 1.0F); } }); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventProjectilesInPortals.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventProjectilesInPortals.java index 032d621ef..e14a9d268 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventProjectilesInPortals.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventProjectilesInPortals.java @@ -13,8 +13,8 @@ public class PreventProjectilesInPortals extends AEFModule implements Listener { public PreventProjectilesInPortals() { - super("preventions.portals.prevent-projectiles-in-portals"); - config.addComment(configPath, "Prevents a lag exploit. Might disable some chunk loader designs."); + super("preventions.portals.prevent-projectiles-in-portals", false, + "Prevents a lag exploit. Might disable some chunk loader designs."); } @Override @@ -22,11 +22,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventSpecificEntitiesInPortals.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventSpecificEntitiesInPortals.java index 4a9befc3d..7c57b825d 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventSpecificEntitiesInPortals.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/portals/PreventSpecificEntitiesInPortals.java @@ -16,20 +16,30 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; public class PreventSpecificEntitiesInPortals extends AEFModule implements Listener { private final Set forbiddenTypes; public PreventSpecificEntitiesInPortals() { - super("preventions.portals.prevent-specific-types"); - config.addComment(configPath + ".enable", """ + super("preventions.portals.prevent-specific-types", true, """ Configure entities here that you suspect might be used in a dupe\s with portals.\s CAUTION: Will kill the entity on folia due to broken portal event.\s There is sadly no other efficient way."""); - this.forbiddenTypes = config.getList(configPath + ".entities", - List.of("DROPPED_ITEM", "FIREWORK", "PRIMED_TNT", "THROWN_EXP_BOTTLE", "EXPERIENCE_ORB", "ARMOR_STAND"), + List defaults = Stream.of( + XEntityType.ITEM, + XEntityType.FIREWORK_ROCKET, + XEntityType.TNT, + XEntityType.EXPERIENCE_BOTTLE, + XEntityType.EXPERIENCE_ORB, + XEntityType.ARMOR_STAND) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .toList(); + this.forbiddenTypes = config.getList(configPath + ".entities", defaults, "Defaults prevent common lag methods.") .stream() .map(configuredType -> { @@ -49,11 +59,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/DisableWitherSkulls.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/DisableWitherSkulls.java deleted file mode 100755 index 890ff9c3d..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/DisableWitherSkulls.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.xginko.aef.modules.preventions.withers; - -import com.cryptomorin.xseries.XEntityType; -import me.xginko.aef.modules.AEFModule; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.ProjectileLaunchEvent; - -public class DisableWitherSkulls extends AEFModule implements Listener { - - public DisableWitherSkulls() { - super("preventions.withers.disable-withers-from-shooting-skulls"); - config.addComment(configPath, "Prevents wither skulls from being shot."); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onProjectileLaunch(ProjectileLaunchEvent event) { - if (event.getEntityType() == XEntityType.WITHER_SKULL.get()) { - event.setCancelled(true); - } - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RateLimitWitherSkulls.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RateLimitWitherSkulls.java index 014448697..ad8d9310a 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RateLimitWitherSkulls.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RateLimitWitherSkulls.java @@ -15,38 +15,50 @@ public class RateLimitWitherSkulls extends AEFModule implements Listener { - private final ExpiringSet targetingPlayers, targetingOther, notTargeting; + private final long playerCooldownMillis, otherCooldownMillis, notargetCooldownMillis; + + private ExpiringSet targetingPlayers, targetingOther, notTargeting; public RateLimitWitherSkulls() { - super("preventions.withers.rate-limit-wither-skulls"); + super("preventions.withers.rate-limit-shooting-skulls", false); config.addComment(configPath + ".enable", """ This can help combat lag caused by a ton of wither skulls\s spawning but weakens withers."""); - this.targetingPlayers = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".player-target-cooldown-in-ticks", 20, """ - Cooldown until another skull can be shot at a player.""")) * 50L)); - this.targetingOther = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".other-target-cooldown-in-ticks", 40, """ - Cooldown until another skull can be shot at anything\s - else other than a player.""")) * 50L)); - this.notTargeting = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".no-target-cooldown-in-ticks", 100, """ - Cooldown when wither has no target.""")) * 50L)); + this.playerCooldownMillis = Math.max(1, config.getInt(configPath + ".player-target-cooldown-in-ticks", 20, + "Cooldown until another skull will be shot at a player")) * 50L; + this.otherCooldownMillis = Math.max(1, config.getInt(configPath + ".other-target-cooldown-in-ticks", 40, + "Cooldown until another skull can be shot at anything \n" + + "else other than a player.")) * 50L; + this.notargetCooldownMillis = Math.max(1, config.getInt(configPath + ".no-target-cooldown-in-ticks", 100, + "Cooldown when wither has no target")) * 50L; } @Override public void enable() { + targetingPlayers = new ExpiringSet<>(Duration.ofMillis(playerCooldownMillis)); + targetingOther = new ExpiringSet<>(Duration.ofMillis(otherCooldownMillis)); + notTargeting = new ExpiringSet<>(Duration.ofMillis(notargetCooldownMillis)); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (targetingPlayers != null) { + targetingPlayers.clear(); + targetingPlayers.cleanUp(); + targetingPlayers = null; + } + if (targetingOther != null) { + targetingOther.clear(); + targetingOther.cleanUp(); + targetingOther = null; + } + if (notTargeting != null) { + notTargeting.clear(); + notTargeting.cleanUp(); + notTargeting = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveAllSkullsPeriodically.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveAllSkullsPeriodically.java deleted file mode 100755 index 8be1e0fdc..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveAllSkullsPeriodically.java +++ /dev/null @@ -1,55 +0,0 @@ -package me.xginko.aef.modules.preventions.withers; - -import io.papermc.paper.threadedregions.scheduler.ScheduledTask; -import me.xginko.aef.modules.AEFModule; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; - -import java.util.function.Consumer; - -public class RemoveAllSkullsPeriodically extends AEFModule implements Consumer { - - private ScheduledTask scheduledTask; - private final long checkPeriod; - - public RemoveAllSkullsPeriodically() { - super("preventions.withers.remove-flying-wither-skulls.periodically-remove-all-flying-skulls"); - config.addComment(configPath + ".enable", "Enable if a lot of wither skulls at spawn are causing lag."); - checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 80); - } - - @Override - public void enable() { - this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() - .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - - @Override - public void disable() { - if (scheduledTask != null) scheduledTask.cancel(); - } - - @Override - public void accept(ScheduledTask task) { - for (World world : plugin.getServer().getWorlds()) { - for (Chunk chunk : world.getLoadedChunks()) { - plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { - for (Entity entity : chunk.getEntities()) { - entity.getScheduler().execute(plugin, () -> { - if (entity.getType().equals(EntityType.WITHER_SKULL)) { - entity.remove(); - } - }, null, 1L); - } - }); - } - } - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkload.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkload.java index 63ccf5640..2155fd509 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkload.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkload.java @@ -7,14 +7,14 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.world.EntitiesLoadEvent; public class RemoveSkullsOnChunkload extends AEFModule implements Listener { public RemoveSkullsOnChunkload() { - super("preventions.withers.remove-flying-wither-skulls.on-chunk-load"); - config.addComment(configPath, """ - Removes wither skulls when the chunk gets loaded.\s + super("preventions.withers.remove-skulls-on-load", true, """ + Removes wither skulls when entities get loaded.\s Use if you have a ton of them at spawn and they are causing lag."""); } @@ -23,21 +23,21 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, true); - } - @Override public void disable() { HandlerList.unregisterAll(this); } - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - private void onChunkLoad(ChunkLoadEvent event) { - if (event.isNewChunk()) return; + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onProjectileLaunch(ProjectileLaunchEvent event) { + if (event.getEntityType() == XEntityType.WITHER_SKULL.get()) { + event.getEntity().setPersistent(false); // Don't save skull when chunk unloads + } + } - for (Entity entity : event.getChunk().getEntities()) { + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntitiesLoad(EntitiesLoadEvent event) { + for (Entity entity : event.getEntities()) { if (entity.getType() == XEntityType.WITHER_SKULL.get()) { entity.getScheduler().execute(plugin, entity::remove, null, 1L); } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkunload.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkunload.java deleted file mode 100755 index 65ba074c7..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkunload.java +++ /dev/null @@ -1,46 +0,0 @@ -package me.xginko.aef.modules.preventions.withers; - -import com.cryptomorin.xseries.XEntityType; -import me.xginko.aef.modules.AEFModule; -import org.bukkit.entity.Entity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkUnloadEvent; - -public class RemoveSkullsOnChunkunload extends AEFModule implements Listener { - - public RemoveSkullsOnChunkunload() { - super("preventions.withers.remove-flying-wither-skulls.on-chunk-unload"); - config.addComment(configPath, """ - Removes wither skulls when the chunk gets unloaded.\s - Use if you have a ton of them at spawn and they are causing lag."""); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - private void onChunkUnload(ChunkUnloadEvent event) { - for (Entity entity : event.getChunk().getEntities()) { - entity.getScheduler().execute(plugin, () -> { - if (entity.getType() == XEntityType.WITHER_SKULL.get()) { - entity.remove(); - } - }, null, 1L); - } - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSkullDropsAtSpawn.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSkullDropsAtSpawn.java new file mode 100755 index 000000000..2d3d11fa1 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSkullDropsAtSpawn.java @@ -0,0 +1,63 @@ +package me.xginko.aef.modules.preventions.withers; + +import com.cryptomorin.xseries.XEntityType; +import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.LocationUtil; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.util.NumberConversions; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WitherSkullDropsAtSpawn extends AEFModule implements Listener { + + private final Map worldsAndTheirRadiuses; + + public WitherSkullDropsAtSpawn() { + super("preventions.withers.disable-item-drops-at-spawn", false, + "Prevents wither skulls from dropping items when they hit a block\n" + + "within a certain radius from 00. Can help with lag."); + Map defaults = new HashMap<>(); + defaults.put("world", 5000); + defaults.put("world_nether", 5000); + defaults.put("world_the_end", 5000); + ConfigSection section = config.getConfigSection(configPath + ".worlds", defaults); + List worlds = section.getKeys(false); + this.worldsAndTheirRadiuses = new HashMap<>(worlds.size()); + for (String world : worlds) { + try { + double radiusSquared = NumberConversions.square(Integer.parseInt(section.getString(world))); + this.worldsAndTheirRadiuses.put(world, radiusSquared); + } catch (NumberFormatException e) { + warn("Radius for world '" + world + "' is not a valid integer."); + } + } + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntityExplode(EntityExplodeEvent event) { + if (event.getEntityType() != XEntityType.WITHER_SKULL.get()) return; + if (!worldsAndTheirRadiuses.containsKey(event.getLocation().getWorld().getName())) return; + + if (LocationUtil.getSquaredDistance2DTo00(event.getLocation()) + <= worldsAndTheirRadiuses.get(event.getLocation().getWorld().getName())) { + event.setYield(0); + } + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSpawningAtSpawn.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSummonAtSpawn.java similarity index 64% rename from AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSpawningAtSpawn.java rename to AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSummonAtSpawn.java index a0811b950..0ac380b22 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSpawningAtSpawn.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSummonAtSpawn.java @@ -6,26 +6,25 @@ import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.LocationUtil; import net.kyori.adventure.text.TextReplacementConfig; -import org.bukkit.Location; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.util.NumberConversions; import java.util.HashMap; +import java.util.List; import java.util.Map; -public class WitherSpawningAtSpawn extends AEFModule implements Listener { +public class WitherSummonAtSpawn extends AEFModule implements Listener { - private final Map worldsAndTheirRadiuses = new HashMap<>(); + private final Map worldsAndTheirRadiuses; private final boolean playersShouldBeInformed; - public WitherSpawningAtSpawn() { - super("preventions.withers.disable-wither-spawning-at-spawn"); - config.addComment(configPath + ".enable", """ + public WitherSummonAtSpawn() { + super("preventions.withers.disable-summon-at-spawn", false, """ Disables spawning withers near a configurable radius around\s spawn. Helps if players are generating endless amounts of withers\s to lag the server."""); @@ -35,10 +34,12 @@ public WitherSpawningAtSpawn() { defaults.put("world_nether", 5000); defaults.put("world_the_end", 5000); ConfigSection section = config.getConfigSection(configPath + ".worlds", defaults); - for (String world : section.getKeys(false)) { + List worlds = section.getKeys(false); + this.worldsAndTheirRadiuses = new HashMap<>(worlds.size()); + for (String world : worlds) { try { - Integer radius = Integer.parseInt(section.getString(world)); - this.worldsAndTheirRadiuses.put(world, radius); + Double radiusSquared = NumberConversions.square(Integer.parseInt(section.getString(world))); + this.worldsAndTheirRadiuses.put(world, radiusSquared); } catch (NumberFormatException e) { warn("Radius for world '" + world + "' is not a valid integer."); } @@ -50,11 +51,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -65,20 +61,17 @@ private void onCreatureSpawn(CreatureSpawnEvent event) { if (event.getEntityType() != XEntityType.WITHER_SKULL.get()) return; if (event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.BUILD_WITHER) return; - final Entity wither = event.getEntity(); - final String world = wither.getWorld().getName(); - if (!worldsAndTheirRadiuses.containsKey(world)) return; - - final Integer disabledRadius = worldsAndTheirRadiuses.get(world); - final Location witherLocation = wither.getLocation(); - if (LocationUtil.getDistance2DTo00(witherLocation) > disabledRadius) return; + String worldName = event.getLocation().getWorld().getName(); + if (!worldsAndTheirRadiuses.containsKey(worldName)) return; + if (LocationUtil.getSquaredDistance2DTo00(event.getLocation()) > worldsAndTheirRadiuses.get(worldName)) return; event.setCancelled(true); if (playersShouldBeInformed) { - for (Player nearbyPlayer : witherLocation.getNearbyPlayers(8)) { + for (Player nearbyPlayer : event.getLocation().getNearbyPlayers(8)) { nearbyPlayer.sendMessage(AnarchyExploitFixes.getLang(nearbyPlayer.locale()).preventions_witherSpawningDisabledInRadius - .replaceText(TextReplacementConfig.builder().matchLiteral("%radius%").replacement(disabledRadius.toString()).build())); + .replaceText(TextReplacementConfig.builder().matchLiteral("%radius%") + .replacement(worldsAndTheirRadiuses.get(worldName).toString()).build())); } } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/KyoriUtil.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/KyoriUtil.java index 0fd315b5e..457bcda5f 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/KyoriUtil.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/KyoriUtil.java @@ -6,7 +6,7 @@ import java.util.Locale; -public class KyoriUtil { +public final class KyoriUtil { public static final TextColor AEF_BLUE = TextColor.fromHexString("#00EDFF"); public static final TextColor AEF_WHITE = TextColor.fromHexString("#E2FDFF"); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/LocationUtil.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/LocationUtil.java index d3b3a6baf..ab9f99635 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/LocationUtil.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/LocationUtil.java @@ -4,8 +4,9 @@ import org.apache.commons.math3.util.FastMath; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.util.NumberConversions; -public class LocationUtil { +public final class LocationUtil { public static String toString(Location location) { return "[" + location.getWorld().getName() + "] x=" + location.getBlockX() + ", y=" + location.getBlockY() + ", z=" + location.getBlockZ(); @@ -16,10 +17,37 @@ public static boolean isNetherCeiling(Location location) { && location.y() > AnarchyExploitFixes.config().nether_ceiling_max_y; } + public static double getSquaredDistance2DTo00(Location location) { + return NumberConversions.square(location.getX()) + NumberConversions.square(location.getZ()); + } + public static double getDistance2DTo00(Location location) { return FastMath.hypot(location.getX(), location.getZ()); } + public static double getRelSquaredDistance2D(Location from, Location to) { + double toX = to.getX(); + double toZ = to.getZ(); + double fromX = from.getX(); + double fromZ = from.getZ(); + + final World.Environment toEnv = to.getWorld().getEnvironment(); + final World.Environment fromEnv = from.getWorld().getEnvironment(); + if (toEnv != fromEnv) { + if (fromEnv == World.Environment.NETHER) { + fromX *= 8; + fromZ *= 8; + } + if (toEnv == World.Environment.NETHER) { + toX *= 8; + toZ *= 8; + } + } + + return NumberConversions.square(toX - fromX) + + NumberConversions.square(toZ - fromZ); + } + public static double getRelDistance2D(Location from, Location to) { double toX = to.x(); double toZ = to.z(); @@ -42,6 +70,30 @@ public static double getRelDistance2D(Location from, Location to) { return FastMath.hypot(toX - fromX, toZ - fromZ); } + public static double getRelSquaredDistance3D(Location from, Location to) { + double toX = to.getX(); + double toZ = to.getZ(); + double fromX = from.getX(); + double fromZ = from.getZ(); + + final World.Environment toEnv = to.getWorld().getEnvironment(); + final World.Environment fromEnv = from.getWorld().getEnvironment(); + if (toEnv != fromEnv) { + if (fromEnv == World.Environment.NETHER) { + fromX *= 8; + fromZ *= 8; + } + if (toEnv == World.Environment.NETHER) { + toX *= 8; + toZ *= 8; + } + } + + return NumberConversions.square(toX - fromX) + + NumberConversions.square(from.getY() - to.getY()) + + NumberConversions.square(toZ - fromZ); + } + public static double getRelDistance3D(Location from, Location to) { double toX = to.x(); double toZ = to.z(); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/enums/AEFKey.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/enums/AEFKey.java similarity index 93% rename from AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/enums/AEFKey.java rename to AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/enums/AEFKey.java index f4306aa22..2cd939106 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/enums/AEFKey.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/utils/enums/AEFKey.java @@ -1,4 +1,4 @@ -package me.xginko.aef.enums; +package me.xginko.aef.utils.enums; import me.xginko.aef.AnarchyExploitFixes; import org.bukkit.Keyed; diff --git a/AnarchyExploitFixesFolia/src/main/resources/config.yml b/AnarchyExploitFixesFolia/src/main/resources/config.yml deleted file mode 100644 index 622889ecd..000000000 --- a/AnarchyExploitFixesFolia/src/main/resources/config.yml +++ /dev/null @@ -1,2273 +0,0 @@ -plugin-version: 2.7.2 -server-version: '1.21-127-4e6a2a1 (MC: 1.21)' - -############## -# Language # -############## -language: - # The default language that will be used if auto-language is set to false - # or no matching language file was found. - default-language: en_us - # If set to true, will display messages based on client language. - auto-language: true - -############# -# General # -############# -general: - # The time in ticks (1 sec = 20 ticks) a checked tps will be cached - # by the plugin. - max-tps-check-interval-in-ticks: 20 - # In case packet modules are causing trouble, you can disable them here. - disable-all-packet-listeners: false - # The Y-level at which the nether ceiling generates the last layer of bedrock - # on your server. - nether-ceiling-y: 127 - # A server restart is required when changing a command's enable status! - commands: - say: - enable: false - # Uses MiniMessage format: https://docs.advntr.dev/minimessage/format.html. - format: 'SERVER: %message%' - help: - # Help command that shows a small command overview for players. - enable: false - toggleconnectionmsgs: - # If you don't use join leave/messages, you can set this to false. - enable: true - -################### -# Miscellaneous # -################### -misc: - join-leave-messages: - # If you want to hide yourself or someone else when logging - # into the game, use these permissions: - # aef.silentJoin, aef.silentLeave - enable: true - # If set to true, players will see join/leave messages by default - # and enter /toggleconnectionmsgs to disable them. - # If set to false will work the other way around. - connection-messages-on-by-default: true - show-in-console: false - first-join-messages: - # Configure message in lang folder. - # You can hide yourself and other players using the permission: - # aef.silentJoin - enable: false - show-in-console: true - kicks: - # Configure mask message in lang folder. - mask-kick-messages: false - prevent-message-kick: - # Cancels the kick for specific kick messages. - enable: false - kick-messages-to-listen-to: - - Kicked for spamming - - Stop spamming! - auto-bed: - # Re-enables SPIGOT-5988, also known as 'auto-bed' - # From Minecraft version 1.16 (≈June 2020) to version 1.17.1(≈October 2021) - # there was a bug (SPIGOT-5988) which did not reset the respawn point of the - # player after death, if his bed was blocked with a shulker. - # After dying a second time, the player will be back at his bed again. - # This bug persisted from the Spigot server to Paper and all its forks until - # October 2021, after which it was fixed by the Spigot development team. - # Attempts by players to reach out to Spigot to allow them to disable the patch - # that fixes the SPIGOT-5988 bug have failed. - # Demonstration of how the patch works: - # https://www.youtube.com/watch?v=3y5SbQXzMss - enable: false - -########## -# Chat # -########## -chat: - command-whitelist: - # This will make it pretty much impossible to find your plugins as - # only the commands you specify will be able to work. - # Allow bypass using permission: aef.bypass.commandwhitelist - enable: false - # Will show logs when a command was denied. - log: false - # Enable only if you have problems with the default commandwhitelist. - # Otherwise not recommended to use. - use-packets: false - # Add all commands you WANT your players to be able to access - # WITHOUT the '/'. Not case sensitive. - whitelisted-commands: - - help - - vote - - kill - - discord - - togglechat - - toggleconnectionmsgs - - toggletells - - togglewhispering - - toggleprivatemsgs - - ignore - - ignorelist - - ignorehard - - toggledeathmsg - - dmt - - worldstats - - stats - - tps - - msg - - whisper - - w - - m - - t - - pm - - tell - - r - - reply - - last - # Add all subcommands you DON'T want your players to be able - # to access. Case sensitive! - blacklisted-subcommands: - - help about - - vote List - - vote Best - - vote Total - - worldstats reload - - stats reload - prevent-scanning-server-plugins: - # Prevents hacked clients running .plugins to find out what plugins - # the server is using. - # Recommended to use in combination with command whitelist. - enable: true - -############ -# Elytra # -############ -elytra: - # NOTE: Set nocheatplus horizontal elytra settings to 500 or higher. - elytra-speed: - # Time in ticks that a chunk has to have been inhabited to count as old chunk. - # Note that the time is incremented once per tick per player within mob spawning - # distance of a chunk. - old-chunk-inhabited-ticks: 200 - # The period in millis players will be checked to determine their speed. - # If you have lagging players with consistent high ping, you can increase this number. - check-period-millis: 500 - # If set to false, will only calculate 2-Dimensional speed without taking height - # changes into consideration. - calculate-3D-speed: false - # Display info in Actionbar while flying. - display-actionbar: true - # Inform flying player if they are in old or new chunks. - display-chunk-info-in-actionbar: true - # Plays XP pickup sound to alert players when theyre going above the limit. - play-sound-when-too-fast: true - sound: ENTITY_EXPERIENCE_ORB_PICKUP - # Recommended to leave false if you dont experience any issues. - teleport-instead-of-canceling-movement: false - Global-Settings: - # Global settings. If nothing else is enabled, this will be used for all environments. - enable: true - # Can be slow with a lot of players. Enable only if needed. - use-bypass-permission: false - deny-elytra-usage: false - speed-old-chunks: 1.81 - speed-new-chunks: 1.81 - enable-bursting: true - burst-speed-old-chunks: 5.0 - burst-speed-old-chunk-TPS: 18.0 - burst-speed-new-chunks: 3.12 - burst-speed-new-chunk-TPS: 19.0 - deny-elytra-on-low-TPS: true - deny-elytra-TPS: 12.0 - also-remove-elytra-on-low-TPS: true - At-Spawn: - # Use separate values for players at spawn. - enable: false - # Radius in blocks around 00 that should count as spawn. - radius: 3000 - # Can be slow with a lot of players. Enable only if needed. - use-bypass-permission: false - deny-elytra-usage: false - speed-old-chunks: 1.0 - speed-new-chunks: 0.8 - deny-elytra-on-low-TPS: true - deny-elytra-TPS: 10.0 - also-remove-elytra-on-low-TPS: true - Nether-Ceiling: - # Use separate values for players above the nether ceiling. - enable: true - # Can be slow with a lot of players. Enable only if needed. - use-bypass-permission: false - deny-elytra-usage: false - speed-old-chunks: 0.5 - speed-new-chunks: 0.5 - enable-bursting: true - burst-speed-old-chunks: 1.0 - burst-speed-old-chunk-TPS: 18.0 - burst-speed-new-chunks: 1.0 - burst-speed-new-chunk-TPS: 18.0 - deny-elytra-on-low-TPS: true - deny-elytra-TPS: 12.0 - also-remove-elytra-on-low-TPS: true - packet-elytra-fly: - # Patches the future/rusherhack/kamiblue 2b2t elytra fly exploit. - patch-packet-elytra-fly: false - # The fly exploit causes the player to constantly toggle gliding. - # If too many glide toggles occur within a timeframe, they are - # most likely using PacketFly. - # Still may trigger false positives when players are jumping and - # sprinting with elytra equipped, so recommended to play around - # with the values. - max-elytra-opens-per-time: 25 - # Time in seconds a elytra open count will be remembered by the plugin. - time-in-seconds: 8 - # Configure message in lang folder. - notify-player-to-disable-packetfly: true - # If enabled, player will be kicked with a message instead of - # getting their elytra dropped. - kick-instead-of-remove-elytra: false - -################## -# Chunk Limits # -################## -chunk-limits: - entity-limits: - dropped-item-limit: - # Limit the amount of dropped items in a chunk to combat lag. - # Be aware this does not prioritize items by value or anything, - # it just deletes whatever happens to get over the limit during - # counting. - enable: false - log-removals: true - max-dropped-items-per-chunk: 200 - # The delay in ticks the plugin will wait after an item in a chunk - # has dropped before the check logic will run. - # This improves performance as there will be no check for each single - # item entity that spawns. - post-item-drop-check-delay-ticks: 60 - # The period in ticks in which all loaded chunks should be regularly - # checked. Keep in mind: A lower number provides more accuracy but is - # also worse for performance. - check-period-in-ticks: 1200 - # Runs item check when a chunk is loaded. - check-on-chunk-load: true - whitelist-specific-item-types: false - # Check the paper api for correct Material enums: - # https://jd.papermc.io/paper/1.20.6/org/bukkit/Material.html - # Make sure your minecraft version is matching as well. - whitelisted-types: - - BLACK_SHULKER_BOX - - BLUE_SHULKER_BOX - - BROWN_SHULKER_BOX - - CYAN_SHULKER_BOX - - GRAY_SHULKER_BOX - - GREEN_SHULKER_BOX - - LIGHT_BLUE_SHULKER_BOX - - LIGHT_GRAY_SHULKER_BOX - - LIME_SHULKER_BOX - - MAGENTA_SHULKER_BOX - - ORANGE_SHULKER_BOX - - PINK_SHULKER_BOX - - PURPLE_SHULKER_BOX - - RED_SHULKER_BOX - - SHULKER_BOX - - WHITE_SHULKER_BOX - - YELLOW_SHULKER_BOX - tile-entity-limit: - # Limit the amount of tile entities in a chunk to prevent lag. - enable: false - log-removals: true - max-tile-entities-per-chunk: 100 - check-period-in-ticks: 20 - villager-limit: - enable: false - max-villagers-per-chunk: 25 - log-removals: false - # Check all chunks every x ticks. - check-period-in-ticks: 600 - # Professions that are in the top of the list are going to be scheduled for - # removal first. - removal-priority: - - NONE - - NITWIT - - SHEPHERD - - FISHERMAN - - BUTCHER - - CARTOGRAPHER - - LEATHERWORKER - - FLETCHER - - MASON - - FARMER - - ARMORER - - TOOLSMITH - - WEAPONSMITH - - CLERIC - - LIBRARIAN - whitelist: - enable: false - professions: - - NONE - - NITWIT - - SHEPHERD - - FISHERMAN - - BUTCHER - - CARTOGRAPHER - - LEATHERWORKER - - FLETCHER - - MASON - - FARMER - - ARMORER - - TOOLSMITH - - WEAPONSMITH - - CLERIC - - LIBRARIAN - non-living-limit: - # Limit the amount of non living entities in a chunk to prevent lag. - # Ignores dropped items. - enable: false - log-removals: true - max-non-living-per-chunk: 100 - check-period-in-ticks: 20 - custom-limit: - # Limit specific entity types per chunk. - enable: false - log-removals: true - # Check all loaded chunks every x ticks. - check-period-in-ticks: 1200 - chunk-age-skip: - enable: true - # How long a chunk has to have been inhabited for it to be checked. - # 1 second = 20 ticks. - min-age-in-ticks: 800 - # When a chunk is loaded, entities inside of it are not necessarily - # loaded as well. Force loading is worse for performance, but there - # might be a scenario where this turns out to be useful. - forceload-entities: false - # Check the paper api for correct EntityType enums: - # https://jd.papermc.io/paper/1.20.6/org/bukkit/entity/EntityType.html - # Make sure your minecraft version is matching as well. - limited-types: - ALLAY: 20 - ARROW: 20 - AXOLOTL: 10 - BAT: 3 - BEE: 15 - BLAZE: 10 - CAT: 10 - CAVE_SPIDER: 10 - CHICKEN: 10 - COD: 6 - COW: 10 - CREEPER: 10 - DOLPHIN: 4 - DONKEY: 10 - DROWNED: 10 - ENDERMAN: 10 - ENDERMITE: 3 - EVOKER: 15 - FIREBALL: 5 - FOX: 10 - FROG: 20 - GLOW_SQUID: 20 - GOAT: 10 - GUARDIAN: 20 - HOGLIN: 10 - HORSE: 10 - HUSK: 10 - IRON_GOLEM: 15 - LLAMA: 10 - MAGMA_CUBE: 10 - MOOSHROOM: 10 - MULE: 10 - OCELOT: 3 - PANDA: 5 - PARROT: 10 - PHANTOM: 10 - PIG: 10 - PIGLIN: 25 - PIGLIN_BRUTE: 10 - PILLAGER: 15 - POLAR_BEAR: 5 - PUFFERFISH: 3 - RABBIT: 5 - RAVAGER: 15 - SALMON: 6 - SHEEP: 10 - SILVERFISH: 3 - SKELETON: 10 - SKELETON_HORSE: 10 - SLIME: 10 - SMALL_FIREBALL: 5 - SNOWBALL: 5 - SPIDER: 10 - SQUID: 20 - STRAY: 10 - STRIDER: 3 - TADPOLE: 20 - TRADER_LLAMA: 10 - TROPICAL_FISH: 6 - TURTLE: 20 - VEX: 15 - VINDICATOR: 15 - WANDERING_TRADER: 10 - WITCH: 15 - WITHER: 16 - WITHER_SKELETON: 10 - WITHER_SKULL: 10 - WOLF: 10 - ZOGLIN: 10 - ZOMBIE: 10 - ZOMBIE_HORSE: 10 - ZOMBIE_VILLAGER: 25 - ZOMBIFIED_PIGLIN: 20 - vehicle-limit: - # Limit the amount of vehicles to prevent some lag machines. - # ex. dispenser that spawns a lot of boats into a single location - # then hitting it, causing all boats to explode in every direction. - enable: false - log-removals: false - max-vehicles-per-chunk: 25 - # 200 ticks = 10 seconds. - check-period-in-ticks: 400 - falling-block-limit: - # Prevent players from placing massive sand chunks, then collapsing - # them to kill the server. - enable: true - log: false - # Removes any falling block if there is more than x blocks actively - # falling in a chunk. - max-falling-gravity-blocks-per-chunk: 60 - # Delay in ticks until the same chunk can be checked again. - # Prevents overchecking, because physics events can be called many - # times in a short time for the same chunk. - chunk-check-delay-in-ticks: 20 - block-limit: - enable: false - # Attempt to prevent ChunkBan / Client FPS Lag - max-blocks-per-chunk: - ACACIA_HANGING_SIGN: 8 - ACACIA_SIGN: 8 - ACACIA_WALL_HANGING_SIGN: 8 - ACACIA_WALL_SIGN: 8 - BAMBOO_HANGING_SIGN: 8 - BAMBOO_SIGN: 8 - BAMBOO_WALL_HANGING_SIGN: 8 - BAMBOO_WALL_SIGN: 8 - BEACON: 32 - BIRCH_HANGING_SIGN: 8 - BIRCH_SIGN: 8 - BIRCH_WALL_HANGING_SIGN: 8 - BIRCH_WALL_SIGN: 8 - BLACK_BANNER: 12 - BLACK_WALL_BANNER: 12 - BLUE_BANNER: 12 - BLUE_WALL_BANNER: 12 - BROWN_BANNER: 12 - BROWN_WALL_BANNER: 12 - CHEST: 500 - CREEPER_HEAD: 16 - CREEPER_WALL_HEAD: 16 - CRIMSON_HANGING_SIGN: 8 - CRIMSON_SIGN: 8 - CRIMSON_WALL_HANGING_SIGN: 8 - CRIMSON_WALL_SIGN: 8 - CYAN_BANNER: 12 - CYAN_WALL_BANNER: 12 - DARK_OAK_HANGING_SIGN: 8 - DARK_OAK_SIGN: 8 - DARK_OAK_WALL_HANGING_SIGN: 8 - DARK_OAK_WALL_SIGN: 8 - DISPENSER: 100 - DRAGON_HEAD: 16 - DRAGON_WALL_HEAD: 16 - ENCHANTING_TABLE: 16 - ENDER_CHEST: 64 - GLOWSTONE: 5000 - GRAY_BANNER: 12 - GRAY_WALL_BANNER: 12 - GREEN_BANNER: 12 - GREEN_WALL_BANNER: 12 - JUNGLE_HANGING_SIGN: 8 - JUNGLE_SIGN: 8 - JUNGLE_WALL_HANGING_SIGN: 8 - JUNGLE_WALL_SIGN: 8 - LIGHT_BLUE_BANNER: 12 - LIGHT_BLUE_WALL_BANNER: 12 - LIGHT_GRAY_BANNER: 12 - LIGHT_GRAY_WALL_BANNER: 12 - LIME_BANNER: 12 - LIME_WALL_BANNER: 12 - MAGENTA_BANNER: 12 - MAGENTA_WALL_BANNER: 12 - MANGROVE_HANGING_SIGN: 8 - MANGROVE_SIGN: 8 - MANGROVE_WALL_HANGING_SIGN: 8 - MANGROVE_WALL_SIGN: 8 - MOVING_PISTON: 32 - OAK_HANGING_SIGN: 8 - OAK_SIGN: 8 - OAK_WALL_HANGING_SIGN: 8 - OAK_WALL_SIGN: 8 - ORANGE_BANNER: 12 - ORANGE_WALL_BANNER: 12 - PIGLIN_HEAD: 16 - PIGLIN_WALL_HEAD: 16 - PINK_BANNER: 12 - PINK_WALL_BANNER: 12 - PISTON: 32 - PISTON_HEAD: 32 - PLAYER_HEAD: 16 - PLAYER_WALL_HEAD: 16 - PURPLE_BANNER: 12 - PURPLE_WALL_BANNER: 12 - RED_BANNER: 12 - RED_WALL_BANNER: 12 - SLIME_BLOCK: 128 - SPRUCE_HANGING_SIGN: 8 - SPRUCE_SIGN: 8 - SPRUCE_WALL_HANGING_SIGN: 8 - SPRUCE_WALL_SIGN: 8 - STICKY_PISTON: 32 - TRAPPED_CHEST: 200 - WARPED_HANGING_SIGN: 8 - WARPED_SIGN: 8 - WARPED_WALL_HANGING_SIGN: 8 - WARPED_WALL_SIGN: 8 - YELLOW_BANNER: 12 - YELLOW_WALL_BANNER: 12 - ZOMBIE_HEAD: 16 - ZOMBIE_WALL_HEAD: 16 - minecart-limit: - # Limit the amount of minecarts to prevent lag caused by collisions. - enable: false - log-removals: false - max-minecarts-per-chunk: 25 - check-period-in-ticks: 400 - exp-bottle-limit: - # Prevent players from crashing the server or other players by - # creating a ton of THROWN_EXP_BOTTLE entities, then loading - # them at once. - # Does not limit the EXP_ORBS, just the bottle entities. - enable: true - log: false - max-exp-bottle-per-chunk: 25 - # 20 ticks = 1 second - check-period-in-ticks: 800 - -##################### -# Lag Preventions # -##################### -lag-preventions: - keep-stash-chunks-loaded: - # Idea by 3b3t admin kumori (Soft1k) - # Improves lag generated by large stash chunks constantly loading and - # unloading by setting them force loaded. This might cause increased ram - # usage, so keep an eye out for that. - enable: false - log: false - # How many container blocks have to be in a chunk for it to be seen - # as a stash chunk to keep force loaded. - container-block-threshold: 50 - # The minimum time in ticks a chunk has to have been inhabited to be checked. - min-chunk-inhabited-time-ticks: 1000 - # The time in minutes a stash chunks will be kept force loaded before - # setting it back to normal. - keep-loaded-minutes: 120 - # Set to false if you want to check more blocks than just tile entities. - # Makes the overall speed of the module faster if set to true. - only-check-tile-entities: true - container-types: - - CHISELED_BOOKSHELF - - DECORATED_POT - - CHEST - - FURNACE - - JUKEBOX - - SHULKER_BOX - - WHITE_SHULKER_BOX - - ORANGE_SHULKER_BOX - - MAGENTA_SHULKER_BOX - - LIGHT_BLUE_SHULKER_BOX - - YELLOW_SHULKER_BOX - - LIME_SHULKER_BOX - - PINK_SHULKER_BOX - - GRAY_SHULKER_BOX - - LIGHT_GRAY_SHULKER_BOX - - CYAN_SHULKER_BOX - - PURPLE_SHULKER_BOX - - BLUE_SHULKER_BOX - - BROWN_SHULKER_BOX - - GREEN_SHULKER_BOX - - RED_SHULKER_BOX - - BLACK_SHULKER_BOX - - HOPPER - - DISPENSER - - DROPPER - - LECTERN - - TRAPPED_CHEST - - CRAFTER - - BREWING_STAND - - BARREL - - SMOKER - - BLAST_FURNACE - # Radiuses around spawn in chunks (not blocks) that should not be checked. - # Worlds not on this list are exempt from all checking. - worlds: - world: 100 - world_the_end: 100 - world_nether: 100 - disable-item-drops-during-large-stash-explosions: - # Explodes containers without dropping items after a certain amount - # of exploded containers per chunk. - enable: false - log: false - # How many container blocks in a chunk can be blown up until items - # no longer drop from them. - min-explosions-before-drops-disable: 6 - # The time in seconds to wait after an explosion for another one to happen. - # If no explosion happens within x seconds after the first one, the count resets to 0. - time-in-seconds: 3 - container-types: - - CHISELED_BOOKSHELF - - DECORATED_POT - - CHEST - - FURNACE - - JUKEBOX - - HOPPER - - DISPENSER - - DROPPER - - LECTERN - - TRAPPED_CHEST - - CRAFTER - - BREWING_STAND - - BARREL - - SMOKER - - BLAST_FURNACE - prevent-lever-spam: - # Rate Limit levers to prevent a lag exploit. - enable: false - show-actionbar: true - kick-player: false - max-lever-usages-per-time: 15 - lever-time-in-ticks: 40 - entity-age-limits: - custom-limits: - # Kill certain entities after a custom amount of ticks lived. - enable: false - log-removals: false - # Check all loaded chunks every x ticks. - check-period-in-ticks: 1200 - # When a chunk is loaded, entities inside of it are not necessarily - # loaded as well. Force loading is worse for performance, but there - # might be a scenario where this turns out to be useful. - forceload-entities: false - # Check the paper api for correct EntityType enums: - # https://jd.papermc.io/paper/1.20/org/bukkit/entity/EntityType.html - # Make sure your minecraft version is matching as well. - limited-types: - ARROW: 120 - FALLING_BLOCK: 160 - SNOWBALL: 100 - SPECTRAL_ARROW: 120 - WITHER_SKULL: 100 - projectile-limit: - # Patches any lag exploit that abuses spawning a ton of projectile entities - # (ex. Snowball exploit).Skips over the following entities: ENDER_PEARL, FISHING_HOOK, WITHER_SKULL - # and ENDER_SIGNAL. You can configure those separately in the custom entity age - # limit section. - enable: false - # (20 ticks = 1 second) Will not touch Ender Pearls - max-alive-time-ticks: 300 - # How frequently we should check all projectiles for their alive time - check-period-seconds: 20 - prevent-flooding-machines: - # Will prevent pistons from pushing waterlogged blocks. - # Stops players from using waterlogged blocks and piston flying - # machines to generate large walls of water that generate lag - # due to the fluid physics. - enable: false - delete-waterlogged-blocks: true - anti-shulker-drops: - # Disables shulkers dropping stored items when blown up. - # This helps fix client- and serverside lag when done often and fast. - enable: false - regional-activity: - block-spread: - # Limits blocks spreading or forming based on world conditions within a - # configurable radius and timeframe to help reduce lag by cancelling burst - # activity hotspots. - # - # Examples: - # - # - Snow forming due to a snow storm. - # - Ice forming in a snowy Biome like Taiga or Tundra. - # - Obsidian / Cobblestone forming due to contact with water. - # - Concrete forming due to mixing of concrete powder and water. - # - Mushrooms spreading. - # - Fire spreading. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times a block can form or spread within the configured - # timeframe before activity will be put on cooldown. - block-form-event-limit: 800 - entity-spawn: - # Limits entity spawning activity within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A creature gets spawned naturally, by spawner or other reasons. - # - An entity gets spawned naturally, by spawner or other reasons. - # This does not include tile entities. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of entity spawns within configured timeframe. - spawn-event-limit: 6000 - entity-targeting: - # Limits entities targeting other entities within a configurable radius - # and timeframe to help reduce lag by cancelling burst activity hotspots. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 14.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times an entity can target another entity within the - # configured timeframe before the area will be put on cooldown. - entity-target-event-limit: 8000 - distance-limit: - global-limit: - enable: false - # The max distance no target should exceed. - # You want this to be higher than your highest max distance - # for a specific mob. - max-target-distance: 20.0 - custom-limits: - enable: true - entities: - SKELETON: 6.0 - WITHER: 8.0 - WITHER_SKELETON: 8.0 - ZOMBIE: 6.0 - ZOMBIE_VILLAGER: 10.0 - ZOMBIFIED_PIGLIN: 8.0 - entity-pathfinding: - # Limits entities deciding to pathfind to a specific location - # within a configurable radius and timeframe to help reduce lag - # by cancelling burst activity hotspots. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 14.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times an entity can decide to start moving - # towards a location within the configured timeframe before the - # area will be put on cooldown. - entity-pathfind-event-limit: 4000 - distance-limit: - global-limit: - enable: false - # The max distance no mob pathfinding should exceed. - # You always want this to be higher than your highest max distance - # for a specific mob. - max-target-distance: 20.0 - custom-limits: - enable: true - entities: - SKELETON: 6.0 - WITHER: 8.0 - WITHER_SKELETON: 8.0 - ZOMBIE: 6.0 - ZOMBIE_VILLAGER: 10.0 - ZOMBIFIED_PIGLIN: 8.0 - sculk-bloom: - # Limits sculk blooming within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - An entity was killed and dropped experience within an 8-block - # radius of a SculkCatalyst. - # - A plugin used SculkCatalyst.bloom(Block, int) - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of sculk bloom events within the configured timeframe. - sculk-bloom-limit: 300 - liquid-spread: - # Limits liquid spreading within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A lava block spreading by flowing. - # - A water block spreading by flowing. - # - (optional) A dragon egg is teleporting from one position to another. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 12.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 100.0 - # Maximum number of times liquids are allowed to spread within the configured - # timeframe before they will be put on cooldown. - liquid-spread-event-limit: 2400 - ignore-dragon-egg: true - redstone: - # Limits redstone activity within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A redstone current changes. - # - A redstone block gets powered on. - # - A redstone block gets powered off. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of redstone events within configured timeframe. - redstone-event-limit: 6000 - noteblocks: - # Limits noteblocks being played within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A noteblock is being played through player interaction. - # - A noteblock is being played through a redstone current. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times a noteblock can be played within the configured - # timeframe before they will be put on cooldown. - noteblock-play-limit: 2800 - explosions: - # Limits explosions within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A block exploding. - # - An entity exploding. - # - An entity making the decision to explode. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of explode events within the configured timeframe - # before the region will be put on cooldown. - explode-event-limit: 500 - pistons: - # Limits piston movement within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A piston extends. - # - A piston retracts. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of piston extend and/or retracts within the - # configured timeframe. - piston-movement-limit: 1000 - block-physics: - # Limits block physics within a configurable radius and timeframe - # to help reduce lag by cancelling burst activity hotspots. - # - # Note: - # - # The event used for this check (BlockPhysicsEvent) is a high frequency event, - # it may be called thousands of times per a second on a busy server. - # Where possible the event may also only be called for the "root" block of - # physics updates in order to limit event spam. - # Physics updates that cause other blocks to change their state may not result - # in an event for each of those blocks (usually adjacent). - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times a physics check can be performed within the configured - # timeframe before they will be put on cooldown. - block-physics-event-limit: 256000 - sculk-sensor: - # Limits sculk activity within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A redstone current changes for a sculk sensor. - # - A physics check is being performed for a sculk sensor. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of sculk events within configured timeframe. - sculk-event-limit: 800 - sculk-blocks: - - SCULK_SENSOR - - SCULK_SHRIEKER - - CALIBRATED_SCULK_SENSOR - -############# -# Patches # -############# -patches: - anti-book-ban: - enable: false - # If set to false, will use UTF-8. - # Charset to use to encode the result of NBTCompound#toString into - # a sequence of bytes. The length of that sequence is then used to - # get the approximate Byte-size of an ItemStack. - # Use the /aef bytesize command to get a better understanding. - use-UTF-16: false - max-book-size: 56000 - # Kicks players when they try to create a book bigger than the limit. - kick-on-too-large-book-edit: true - max-author-chars: 32 - max-title-chars: 32 - max-pages: 100 - max-item-size: 56000 - max-inventory-size: 2050000 - # How long in ticks a dropped item's size should be cached after - # checking. - dropped-items-size-cache-ticks: 120 - # How long in ticks a player's inventory size should be cached after - # checking. - player-inventory-size-cache-ticks: 20 - pearl-phase: - # Attempts to patch a pearl phasing exploit by cancelling the teleport - # if the pearl is thrown at or near a specific block. - # At the time of the creation of this module, this is an issue with NoCheatPlus. - enable: false - # How many blocks around the teleport location should be searched - # for potential glitch blocks if the teleport location isn't one itself. - search-radius: 2 - maximum-distance-to-cancel-teleport: 3.0 - glitchy-materials: - - ACACIA_PRESSURE_PLATE - - ACACIA_SLAB - - ACACIA_TRAPDOOR - - ANDESITE_SLAB - - BAMBOO_MOSAIC_SLAB - - BAMBOO_PRESSURE_PLATE - - BAMBOO_SLAB - - BAMBOO_TRAPDOOR - - BIRCH_PRESSURE_PLATE - - BIRCH_SLAB - - BIRCH_TRAPDOOR - - BLACKSTONE_SLAB - - BRICK_SLAB - - CALIBRATED_SCULK_SENSOR - - CHERRY_PRESSURE_PLATE - - CHERRY_SLAB - - CHERRY_TRAPDOOR - - COBBLED_DEEPSLATE_SLAB - - COBBLESTONE_SLAB - - COBWEB - - COPPER_TRAPDOOR - - CRIMSON_PRESSURE_PLATE - - CRIMSON_SLAB - - CRIMSON_TRAPDOOR - - CUT_COPPER_SLAB - - CUT_RED_SANDSTONE_SLAB - - CUT_SANDSTONE_SLAB - - DARK_OAK_PRESSURE_PLATE - - DARK_OAK_SLAB - - DARK_OAK_TRAPDOOR - - DARK_PRISMARINE_SLAB - - DEEPSLATE_BRICK_SLAB - - DEEPSLATE_TILE_SLAB - - DIORITE_SLAB - - END_STONE_BRICK_SLAB - - EXPOSED_COPPER_TRAPDOOR - - EXPOSED_CUT_COPPER_SLAB - - GRANITE_SLAB - - HEAVY_WEIGHTED_PRESSURE_PLATE - - IRON_TRAPDOOR - - JUNGLE_PRESSURE_PLATE - - JUNGLE_SLAB - - JUNGLE_TRAPDOOR - - LIGHT_WEIGHTED_PRESSURE_PLATE - - MANGROVE_PRESSURE_PLATE - - MANGROVE_SLAB - - MANGROVE_TRAPDOOR - - MOSSY_COBBLESTONE_SLAB - - MOSSY_STONE_BRICK_SLAB - - MUD_BRICK_SLAB - - NETHER_BRICK_SLAB - - OAK_PRESSURE_PLATE - - OAK_SLAB - - OAK_TRAPDOOR - - OXIDIZED_COPPER_TRAPDOOR - - OXIDIZED_CUT_COPPER_SLAB - - PETRIFIED_OAK_SLAB - - POLISHED_ANDESITE_SLAB - - POLISHED_BLACKSTONE_BRICK_SLAB - - POLISHED_BLACKSTONE_PRESSURE_PLATE - - POLISHED_BLACKSTONE_SLAB - - POLISHED_DEEPSLATE_SLAB - - POLISHED_DIORITE_SLAB - - POLISHED_GRANITE_SLAB - - POLISHED_TUFF_SLAB - - POWDER_SNOW - - PRISMARINE_BRICK_SLAB - - PRISMARINE_SLAB - - PURPUR_SLAB - - QUARTZ_SLAB - - RED_NETHER_BRICK_SLAB - - RED_SANDSTONE_SLAB - - SANDSTONE_SLAB - - SCULK_SENSOR - - SCULK_SHRIEKER - - SMOOTH_QUARTZ_SLAB - - SMOOTH_RED_SANDSTONE_SLAB - - SMOOTH_SANDSTONE_SLAB - - SMOOTH_STONE_SLAB - - SPRUCE_PRESSURE_PLATE - - SPRUCE_SLAB - - SPRUCE_TRAPDOOR - - STONE_BRICK_SLAB - - STONE_PRESSURE_PLATE - - STONE_SLAB - - TUFF_BRICK_SLAB - - TUFF_SLAB - - WARPED_PRESSURE_PLATE - - WARPED_SLAB - - WARPED_TRAPDOOR - - WAXED_COPPER_TRAPDOOR - - WAXED_CUT_COPPER_SLAB - - WAXED_EXPOSED_COPPER_TRAPDOOR - - WAXED_EXPOSED_CUT_COPPER_SLAB - - WAXED_OXIDIZED_COPPER_TRAPDOOR - - WAXED_OXIDIZED_CUT_COPPER_SLAB - - WAXED_WEATHERED_COPPER_TRAPDOOR - - WAXED_WEATHERED_CUT_COPPER_SLAB - - WEATHERED_COPPER_TRAPDOOR - - WEATHERED_CUT_COPPER_SLAB - prevent-command-sign: - # Patch signs that have run_command NBT tags attached, allowing the - # to run a command with operator permissions on click. - # Recommended to enable if you had a rogue admin or backdoor incident. - enable: true - prevent-fast-world-teleport-crash: - # Prevents crash methods that involve very fast teleporting between - # different worlds in a short time. - enable: false - # Time in milliseconds until an entity can teleport to another - # world again. - teleport-delay-millis: 1000 - log: false - prevent-teleport-coordinate-exploit: - # Patches coordinate exploit for teleportation commands such as /tpa, - # /home AS WELL as respawn exploits. - # This is done by vanishing the player for x ticks before teleporting. - enable: false - min-distance-to-vanish-player: 100 - teleport-vanish-time-in-ticks: 10 - # Removes entities or players if they are invalid, dead or not located - # within a ticking chunk. Not sure if this works. - experimental-godmode-patch: false - tab-complete-crash-patch: - # Patches two lag exploits and an instant server shutdown exploit that - # works by sending a malicious TabComplete packet that triggers a - # StackOverflowError inside the TagParser class. - enable: true - log: false - kick-player: false - remove-beehive-coordinates: - # Patches an exploit that allows players to obtain another player's - # coordinates by trading them for Beehives or Beenests. - # If the traded item contains any bees, the stored bee's NBT data can - # then be read from the item. - # This data includes, but is not limited to: - # - XYZ coordinates of where the bee has its hive - # - XYZ of the bee's last coordinates before entering it's hive - # - XYZ coordinates of where the bee last visited a flower - # - XYZ coordinates of where the bee was first spawned into existence - # - UID of the world the bee was first spawned into existence - enable: true - # The NBT tags to filter from the item. These are the Keys that hold - # the position data. You may add more tags you want removed here. - tags: - - Pos - - HivePos - - FlowerPos - - Paper.Origin - - Paper.OriginWorld - - WorldUUIDMost - - WorldUUIDLeast - window-click-crash-patch: - # Patches a variety of different lag and crash methods that work - # by sending invalid Window Click packets, causing the server to - # dump error logs until it runs out of memory. - enable: true - log: false - kick-player: false - map-cursor-lag-patch: - # Patches the famous stacked map cursor lag that causes both - # client and server crashes. - enable: false - inventory-lag: - # Checks if a player is requesting unusual amounts of traffic from the server - # using ItemStacks. - # If a player exceeds the limit, they will be put on a cooldown, during which - # they will be very limited in terms of ItemStack or Inventory interactions. - enable: false - # For debug purposes. Don't leave enabled for too long as it is very spammy. - log: false - # Whether to immediately close any open inventory of the player on limit exceed - # Note: Closing has to be scheduled so it will take a bit if the server is heavily - # lagging. - close-open-inventory: true - # The time in millis in which to check if the player exceeded the limit. - # Needs to be at least as long as your lockout duration millis. - byte-data-keep-time-millis: 30000 - rate-limit: - # The limit in bytes the server has sent the server in the form of ItemStacks, - # before the player will be put on a rate-limit. - # Should always be lower than your lockout bytesize limit. - bytesize-limit: 8000000 - # The time in millis in which a player is allowed to open x amounts of windows - # but not more. - timeframe-millis: 2500 - # The amount of windows that can be opened during the timeframe-millis. - max-window-opens-per-timeframe: 2 - lockout: - # The upper limit in bytes a player is allowed to request from the server - # within the configured timeframe before he will be put on cooldown. - # During the cooldown, he will not be able to open any inventory screens - # or interact with items. - bytesize-limit: 24000000 - # The time in milliseconds the player will have to wait before - # being able to open an inventory again after he exceeded the limit. - duration-millis: 15000 - check-packets: - - SET_SLOT - - WINDOW_ITEMS - sequence-crash-patch: - # Patches a variety of lag/crash exploits that involves sending packets - # with invalid sequences. - enable: true - log: false - kick-player: false - sign-lag: - # Patches a lag exploit that involves sending specific oversized - # sign edit packets. - enable: true - # How many ticks a player needs to wait to be able to send - # another sign update packet (renaming or writing). - packet-delay-in-ticks: 10 - # Vanilla limit is 384 characters per line, which can be too much. - line-character-limit: 80 - # General char limit for all lines combined. - total-char-limit: 384 - log: false - kick-player: false - beehive-crash-patch: - # Patches a server crash exploit exclusive to Purpur servers. - # This exploit works due to PurpurClient having a feature that - # lets clients request stored data of a clicked beehive from - # the server. The server does not check how far the clicked - # beehive is away from the client enabling a malicious sender - # to load chunks very fast at far away locations by telling - # the server it clicked a beehive there. - enable: false - channel: purpur:beehive_c2s - max-distance: 24 - log: false - kick-player: false - -############## -# Illegals # -############## -illegals: - remove-placed-blocks: - on-chunkload: - # Remove illegally placed blocks on chunkload. - enable: false - # Enter PLAYER_HEAD here if you want to remove placed playerheads. - blocks-to-remove: - - PLAYER_HEAD - - CHAIN_COMMAND_BLOCK - - COMMAND_BLOCK - - COMMAND_BLOCK_MINECART - - REPEATING_COMMAND_BLOCK - - BEDROCK - - BARRIER - exempted-worlds: - - exampleworld1 - - exampleworld2 - pause-on-low-TPS: false - pause-TPS: 14.0 - periodically: - enable: false - # Enter PLAYER_HEAD here if you want to remove placed playerheads. - blocks-to-remove: - - PLAYER_HEAD - - CHAIN_COMMAND_BLOCK - - COMMAND_BLOCK - - COMMAND_BLOCK_MINECART - - REPEATING_COMMAND_BLOCK - - BEDROCK - - BARRIER - exempted-worlds: - - exampleworld1 - - exampleworld2 - check-period-in-seconds: 10 - pause-on-low-TPS: false - pause-TPS: 14.0 - remove-unnatural-spawners-on-chunkload: - enable: false - pause-on-low-TPS: false - pause-TPS: 14.0 - # You can add or remove as much world names here as you want. - natural-spawner-types-per-world: - world: - - SKELETON - - ZOMBIE - - SILVERFISH - - SPIDER - - CAVE_SPIDER - world_the_end: - - SKELETON - - SPIDER - world_nether: - - BLAZE - - MAGMA_CUBE - nbt: - ban-custom-tags: - # Bypass permission: aef.bypass.illegal.nbt.custom - # Deletes items that have one or more of the configured tags. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - # The exact, case sensitive value of the nbt tag. - tags: - - dmg - item-whitelist-enabled: false - use-as-blacklist-instead: false - whitelisted-items: - - GOLDEN_APPLE - impossibly-stored-items: - # Bypass permission: aef.bypass.illegal.nbt.storeditems - # Prevents usage of or deletes storage items that have been pre-filled - # with items using NBT tags. These can only be created by players with - # creative access. - # Most commonly dispensers, droppers and chests containing kit shulkers - # are created but there are more combinations possible. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - # The exact name of the nbt tag that signals items are stored inside. - tag: BlockEntityTag - check-stored-items: false - storage-types: - - BARREL - - BLAST_FURNACE - - BREWING_STAND - - CHEST - - CHISELED_BOOKSHELF - - CRAFTER - - DECORATED_POT - - DISPENSER - - DROPPER - - FURNACE - - HOPPER - - JUKEBOX - - LECTERN - - SMOKER - - TRAPPED_CHEST - command-items: - # Bypass permission: aef.bypass.illegal.nbt.commanditem - # Deletes items with commands in their NBT data that run as operator. - # These can only be created by players with creative access. - # Most common items are books, since it allows storing multiple commands. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - enchantments: - inapplicable-enchants: - # Bypass permission: aef.bypass.illegal.enchants.inapplicable - # Reverts or prevents usage of ItemStacks with Enchantments that - # cannot be applied to that ItemStack in vanilla survival minecraft. - # Examples: A helmet with sharpness or a block of stone with fortune. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - item-whitelist-enabled: true - use-as-blacklist-instead: false - whitelisted-items: - - GOLDEN_APPLE - higher-enchants: - # Bypass permission: aef.bypass.illegal.enchants.higher - # Reverts or prevents usage of ItemStacks with Enchantments higher - # than the natural, in vanilla survival obtainable level (aka 32ks / 255s). - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - only-specific-enchants: false - specific-enchants: - - DIG_SPEED - item-whitelist-enabled: true - use-as-blacklist-instead: false - whitelisted-items: - - GOLDEN_APPLE - incompatible-enchants: - # Bypass permission: aef.bypass.illegal.enchants.incompatible - # Reverts or prevents usage of ItemStacks with Enchantments that - # cannot coexist in vanilla survival minecraft. - # Examples: A bow with mending and infinity or armor with every - # protection enchantment. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - item-whitelist-enabled: true - use-as-blacklist-instead: false - whitelisted-items: - - BOW - attribute-modifiers: - # Bypass permission: aef.bypass.illegal.attributes - # Prevents usage of or reverts items with any attribute modifiers - # or item flags. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - item-whitelist-enabled: false - use-as-blacklist-instead: true - check-stored-items: false - whitelisted-items: - - TOTEM_OF_UNDYING - ban-player-heads: - # Bypass permission: aef.bypass.illegal.playerhead - # Deletes or prevents usage of player heads. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - # Will delete shulker/bundle if they contain any player heads. - check-stored-items: false - ban-specific-materials: - # Bypass permission: aef.bypass.illegal.bannedmaterial - # Prevents usage of or deletes items with material that you do not want - # your players to be able to use. - # Useful if your players have blocks that shouldn't be obtainable in survival. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - banned-materials: - - CHAIN_COMMAND_BLOCK - - COMMAND_BLOCK - - COMMAND_BLOCK_MINECART - - REPEATING_COMMAND_BLOCK - - BEDROCK - - BARRIER - - STRUCTURE_BLOCK - - STRUCTURE_VOID - - END_PORTAL_FRAME - - END_PORTAL - - NETHER_PORTAL - - LIGHT - potions: - # Bypass permission: aef.bypass.illegal.potions - # Prevents usage of or reverts items with any attribute modifiers - # or item flags. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - ban-spawn-eggs: - # Bypass permission: aef.bypass.illegal.spawnegg - # Deletes or prevents usage of spawn eggs. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - # If remove-spawn-eggs is set to true Will delete shulker/bundle - # should they contain any spawneggs. - check-stored-items: false - whitelisted-items: - - VILLAGER_SPAWN_EGG - banned-item-names: - # Bypass permission: aef.bypass.illegal.bannedname - # Resets an item's name (or deletes the item) if it matches one of - # the configured regexes. - # Regexes can be complex. Use a tool like https://regex101.com/ or - # ChatGPT for good results. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - # Will delete the item instead of resetting the name. - delete-item: false - regex: - - (?i)illegalstring - whitelisted-items: - - DIRT - illegally-stacked-items: - # Bypass permission: aef.bypass.illegal.overstacked - # Prevents usage of or reverts items with a higher or lower - # stack size than their vanilla limit. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - item-whitelist-enabled: false - use-as-blacklist-instead: true - check-stored-items: false - whitelisted-items: - - TOTEM_OF_UNDYING - revert-unbreakables: - # Bypass permission: aef.bypass.illegal.unbreakable - # Deletes and prevents usage of unbreakable items. - # This can be anything from items with illegal damage attributes to - # Metadata/NBT tags. - # Note: Due to the limitations of the API, we can only fully prevent - # usage of these items by deleting them. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - item-whitelist-enabled: false - use-as-blacklist-instead: false - # Will delete shulkers and bundles if they contain unbreakables. - check-stored-items: false - whitelisted-items: - - DIAMOND_CHESTPLATE - -###################### -# Dupe Preventions # -###################### -dupe-preventions: - # Prevent any possible dupes involving chested entities by making - # it impossible to put a chest on them. - # Only do this if you have reason to believe a dupe like that exists - # on your server. - prevent-chests-on-living-entities: false - # Closes open inventories of all entities that are in a chunk - # that will be unloaded. - close-entity-inventories-on-chunk-unload: false - # Prevents entities that can carry chests from using portals to - # block some common dupe tactics. - # CAUTION: Will remove chests and their contents from a chested - # entity if it touches a portal on Folia! - prevent-chested-living-entities-in-portals: false - # Closes open inventories of entities that disappeared when the - # player riding it disconnects. - close-entity-inventories-on-player-disconnect: false - -################# -# Preventions # -################# -preventions: - withers: - disable-wither-spawning-at-spawn: - # Disables spawning withers near a configurable radius around - # spawn. Helps if players are generating endless amounts of withers - # to lag the server. - enable: false - inform-players: true - worlds: - world: 5000 - world_the_end: 5000 - world_nether: 5000 - remove-flying-wither-skulls: - # Removes wither skulls when the chunk gets unloaded. - # Use if you have a ton of them at spawn and they are causing lag. - on-chunk-unload: false - # Removes wither skulls when the chunk gets loaded. - # Use if you have a ton of them at spawn and they are causing lag. - on-chunk-load: true - periodically-remove-all-flying-skulls: - # Enable if a lot of wither skulls at spawn are causing lag. - enable: false - check-period-in-ticks: 80 - # Prevents wither skulls from being shot. - disable-withers-from-shooting-skulls: false - rate-limit-wither-skulls: - # This can help combat lag caused by a ton of wither skulls - # spawning but weakens withers. - enable: false - # Cooldown until another skull can be shot at a player. - player-target-cooldown-in-ticks: 20 - # Cooldown until another skull can be shot at anything - # else other than a player. - other-target-cooldown-in-ticks: 40 - # Cooldown when wither has no target. - no-target-cooldown-in-ticks: 100 - portals: - prevent-specific-types: - # Configure entities here that you suspect might be used in a dupe - # with portals. - # CAUTION: Will kill the entity on folia due to broken portal event. - # There is sadly no other efficient way. - enable: true - # Defaults prevent common lag methods. - entities: - - DROPPED_ITEM - - FIREWORK - - PRIMED_TNT - - THROWN_EXP_BOTTLE - - EXPERIENCE_ORB - - ARMOR_STAND - # Only enable if you must. Does not affect players. - # CAUTION: Will kill the entity on folia due to broken portal event. - prevent-all-entities-in-portals: false - prevent-destroying-end-portals: - enable: true - show-logs: true - end: - bedrock-protection-radius-blocks: 8 - # Add block locations that should be protected as well. - # Format: ::: - # If you don't want to use this, just configure an empty list: - # pillar-blocks: [] - pillar-blocks: - - world_the_end:143:140:-50 - - world_the_end:112:90:-90 - prevent-portal-traps: - # Teleports a player back to the original location if they have been - # standing in a portal for too long. - enable: false - wait-time-until-tp-back-in-seconds: 10 - # Prevents a lag exploit. Might disable some chunk loader designs. - prevent-projectiles-in-portals: false - permanent-block-breaking: - by-placing-piston-on-retract: - enable: true - whitelisted-worlds: - - example_world_name - by-exploding-pistons: - enable: true - whitelisted-worlds: - - example_world_name - # If enabled, will only protect portals and end gateways - only-for-portals-and-gateways: false - by-growing-structures: - # Prevents removal of permanent blocks by growing structures - # like mushrooms into them. - enable: true - prevent-opped-players: - # Useful if you suspect a backdoor has happened. - enable: false - log: false - whitelisted-players: - - Notch - prevent-nether-roof: - # Prevent players from going above the nether roof. - enable: true - safely-teleport-players: true - anti-bed-trap: - # Resets a players bed respawn they die too many times within - # a certain timeframe. - enable: false - # Amount of times player can die until he is determined as bed-trapped. - max-deaths-per-time: 7 - # "Time until death counter will be reset again. - time-in-seconds: 5 - log: false - prevent-non-survival-players: - # Checks if player is in survival and if not, puts him back into survival. - # Useful if you had a backdoor incident. - enable: false - log: false - whitelisted-players: - - Notch - -############ -# Combat # -############ -combat: - silent-swap-delay: - enable: false - # The delay in millis a player cant swap hotbar items after placing - # a block, clicking a block (for example to place a crystal) or - # damaging an entity. (50 ms = 1 tick) - min-swap-delay-millis: 40 - prevent-bow-bomb: - enable: false - # Fully pulled bow is ~9-10. 15 is default just to be safe. - max-bow-squared-velocity: 15 - portal-god-mode-patch: - # Prevents an exploit that allows players to stand in nether portals and not - # take damage indefinitely by just never sending a TeleportConfirm packet to - # the server. - # A similar method is used for the chorus tp exploit, which is not covered - # by this module. - enable: false - # If the player stays inside the nether portal for this time without teleporting, - # the portal will be broken, making the player inside vulnerable again. - # Nether portal teleports normally happen within ~3s after enter, so 5s (100ticks) - # should be a safe value. - break-portal-delay-ticks: 100 - crystal-aura: - piston-aura-delay: - # Rate-limits pistons that extend into crystals. - enable: false - piston-extend-delay-in-ticks: 40 - regular-delay: - enable: false - # Can help with desync but recommended to leave off unless you have issues. - update-inventory-on-cancel: false - global: - enable: false - # 1 tick = 50 ms - place-delay-millis: 0 - break-delay-millis: 200 - main-hand: - enable: false - # 1 tick = 50 ms - place-delay-millis: 0 - break-delay-millis: 200 - off-hand: - enable: false - # 1 tick = 50 ms - place-delay-millis: 0 - break-delay-millis: 200 - prevent-burrow: - enable: false - # 1.0 = Half a heart of damage every time you move. - damage-when-moving: 1.0 - teleport-above-block: true - # Prevent burrow even if there is a block above the block they - # are burrowing in. - # Please note this may allow creating an "elevator", players will - # keep teleporting up until they hit air. - prevent-if-block-above-burrow: false - break-anvil-instead-of-teleport: true - # Needs to be enabled to prevent a bug where players are teleported - # above a slab when the slab is underwater. - allow-slabs-in-burrow: true - ignored-materials: - - BLACK_SHULKER_BOX - - BLUE_SHULKER_BOX - - BROWN_SHULKER_BOX - - CYAN_SHULKER_BOX - - GRAY_SHULKER_BOX - - GREEN_SHULKER_BOX - - LIGHT_BLUE_SHULKER_BOX - - LIGHT_GRAY_SHULKER_BOX - - LIME_SHULKER_BOX - - MAGENTA_SHULKER_BOX - - ORANGE_SHULKER_BOX - - PINK_SHULKER_BOX - - PURPLE_SHULKER_BOX - - RED_SHULKER_BOX - - SHULKER_BOX - - WHITE_SHULKER_BOX - - YELLOW_SHULKER_BOX - - AIR - - DIRT - - DIRT_PATH - - SAND - - GRAVEL - multi-task-patch: - enable: false - piston-push: - # Disables pistons from extending if it would push certain configured entities. - # This can be used to prevent players from pushing other players out of burrows, by - # configuring PLAYER, or to disable piston-crystal by adding ENDER_CRYSTAL to the list. - enable: false - piston-push-blocked-entities: - - PLAYER - anchor-aura-delay: - enable: false - # Can help with desync but recommended to leave off unless you have issues. - update-inventory-on-cancel: false - global: - enable: false - # 1 tick = 50 ms - place-delay-millis: 400 - break-delay-millis: 0 - main-hand: - enable: false - # 1 tick = 50 ms - place-delay-millis: 400 - break-delay-millis: 0 - off-hand: - enable: false - # 1 tick = 50 ms - place-delay-millis: 400 - break-delay-millis: 0 - bed-aura-delay: - enable: false - # Can help with desync but recommended to leave off unless you have issues. - update-inventory-on-cancel: false - global: - enable: false - # 1 tick = 50 ms - place-delay-millis: 250 - break-delay-millis: 0 - main-hand: - enable: false - # 1 tick = 50 ms - place-delay-millis: 250 - break-delay-millis: 0 - off-hand: - enable: false - # 1 tick = 50 ms - place-delay-millis: 250 - break-delay-millis: 0 - -############# -# Bedrock # -############# -bedrock: - fill-in-bedrock: - overworld-floor: - periodically-check-and-fill: - # Only checks loaded chunks. - enable: false - check-period-in-seconds: 10 - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - # Pauses the task during low tps to avoid lag. - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - fill-on-chunkload: - enable: false - # Recommended to leave off. Only useful if world generation is broken. - also-check-new-chunks: false - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - nether-ceiling: - periodically-check-and-fill: - # Only checks loaded chunks. - enable: false - check-period-in-seconds: 10 - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - fill-on-chunkload: - enable: false - # Recommended to leave off. Only useful if world generation is broken. - also-check-new-chunks: false - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - nether-floor: - periodically-check-and-fill: - # Only checks loaded chunks. - enable: false - check-period-in-seconds: 10 - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - fill-on-chunkload: - enable: false - # Recommended to leave off. Only useful if world generation is broken. - also-check-new-chunks: false - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - prevent-going-below-bedrock-floor: - # Prevents players from going below the bedrock floor. - enable: true - # Whether to make player leave their vehicle. - leave-vehicle: true - # Whether to close the player's elytra if they were flying. - stop-elytra: true - # Teleport player on top of that bedrock - teleport: true - # 1.0 = Half a heart of damage every time you move. Set 0 to disable - damage-when-moving: 8.0 - # Whether the bedrock hole should be filled or not. - fill-bedrock-hole: true - exempted-worlds: - - world_the_end - - skyblock_world - filler-material: BEDROCK diff --git a/AnarchyExploitFixesFolia/src/main/resources/plugin.yml b/AnarchyExploitFixesFolia/src/main/resources/plugin.yml index 47a79dd5f..aff614a13 100755 --- a/AnarchyExploitFixesFolia/src/main/resources/plugin.yml +++ b/AnarchyExploitFixesFolia/src/main/resources/plugin.yml @@ -6,6 +6,7 @@ authors: [ xGinko, moo ] description: ${description} softdepend: - packetevents + - LuckPerms api-version: '1.19' folia-supported: true website: ${url} \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/build.gradle.kts b/AnarchyExploitFixesLegacy/build.gradle.kts index 66dd01ba9..327191e42 100755 --- a/AnarchyExploitFixesLegacy/build.gradle.kts +++ b/AnarchyExploitFixesLegacy/build.gradle.kts @@ -21,7 +21,6 @@ tasks { archiveFileName = "${rootProject.name}-${project.name}-${project.version}.${archiveExtension.get()}" exclude( "com/cryptomorin/xseries/XBiome*", - "com/cryptomorin/xseries/XPotion*", "com/cryptomorin/xseries/NMSExtras*", "com/cryptomorin/xseries/NoteBlockMusic*", "com/cryptomorin/xseries/SkullCacheListener*" diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index 7253574de..bb0a52107 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -1,14 +1,15 @@ package me.xginko.aef; import com.github.retrooper.packetevents.PacketEvents; -import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import de.tr7zw.changeme.nbtapi.NBT; import me.xginko.aef.commands.AEFCommand; import me.xginko.aef.config.Config; import me.xginko.aef.config.Datastore; import me.xginko.aef.config.LanguageCache; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.permissions.PermissionHandler; import me.xginko.aef.utils.PlatformUtil; import me.xginko.aef.utils.tickdata.TickReporter; import org.apache.logging.log4j.Level; @@ -23,8 +24,6 @@ import java.io.File; import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.util.Arrays; import java.util.Collections; @@ -45,36 +44,39 @@ public final class AnarchyExploitFixes extends JavaPlugin { private static Map languageCacheMap; private static Config config; private static Datastore datastore; + private static TickReporter tickReporter; - private static CachingPermTool cachingPermTool; + private static PermissionHandler permissionHandler; private static Logger prefixedLogger, unPrefixedLogger; + private static Metrics metrics; private static boolean isPacketEventsInstalled; @Override public void onLoad() { PlatformUtil.load(); - prefixedLogger = LoggerFactory.getLogger(getLogger().getName()); - unPrefixedLogger = LoggerFactory.getLogger(""); - // Disable logging for some shaded libraries as those can get very verbose - String shadedLibs = getClass().getPackage().getName() + ".libs"; - Configurator.setLevel(shadedLibs + ".reflections.Reflections", Level.OFF); - Configurator.setLevel(shadedLibs + ".zaxxer.hikari.pool.PoolBase", Level.OFF); - Configurator.setLevel(shadedLibs + ".zaxxer.hikari.pool.HikariPool", Level.OFF); - Configurator.setLevel(shadedLibs + ".zaxxer.hikari.HikariDataSource", Level.OFF); - Configurator.setLevel(shadedLibs + ".zaxxer.hikari.HikariConfig", Level.OFF); - Configurator.setLevel(shadedLibs + ".zaxxer.hikari.util.DriverDataSource", Level.OFF); - isPacketEventsInstalled = getServer().getPluginManager().getPlugin("packetevents") != null; - if (isPacketEventsInstalled) { - // Configure and load packetevents - PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this)); - PacketEvents.getAPI().getSettings().kickOnPacketException(true).reEncodeByDefault(false).checkForUpdates(false); - PacketEvents.getAPI().load(); - } + // Disable info logging for Reflections because it does not provide additional value to the user and makes startup log look ugly. + Configurator.setLevel(AnarchyExploitFixes.class.getPackage().getName() + ".libs.reflections.Reflections", Level.WARN); } @Override public void onEnable() { + if (!PlatformUtil.isPaper()) { + getLogger().severe("This plugin depends on Paper's API, which is not present on your server."); + getServer().getPluginManager().disablePlugin(this); + return; + } + + if (PlatformUtil.isFolia()) { + getLogger().severe("Please use the Folia jar instead of modifying the plugin.yml."); + getServer().getPluginManager().disablePlugin(this); + return; + } + + prefixedLogger = LoggerFactory.getLogger(getLogger().getName()); + unPrefixedLogger = LoggerFactory.getLogger(""); + + isPacketEventsInstalled = getServer().getPluginManager().getPlugin("packetevents") != null; if (!isPacketEventsInstalled) { Stream.of(" ", " _ _ _ _ _ ", @@ -94,10 +96,6 @@ public void onEnable() { return; } - instance = this; - cachingPermTool = CachingPermTool.enable(this); - metrics = new Metrics(this, 8700); - Stream.of(" ", " ", " █████ ███████ ███████ ", @@ -109,29 +107,32 @@ public void onEnable() { " " ).forEach(prefixedLogger::info); - if (!PlatformUtil.isPaper()) { - prefixedLogger.error("This plugin depends on Paper's API, which is not present on your server."); - getServer().getPluginManager().disablePlugin(this); - return; - } - - prefixedLogger.info("Detected Version 1.{}.{}", PlatformUtil.getMinecraftVersion(), PlatformUtil.getMinecraftPatchVersion()); - - if (PlatformUtil.getMinecraftVersion() < 12) { - prefixedLogger.warn("This version is unsupported. Expect issues."); - } else if (PlatformUtil.getMinecraftVersion() > 19) { + ServerVersion serverVersion = PacketEvents.getAPI().getServerManager().getVersion(); + prefixedLogger.info("Detected {} {}", PlatformUtil.getServerType().niceName(), + serverVersion.name().replace("V_", "").replace('_', '.')); + if (serverVersion.isNewerThan(ServerVersion.V_1_19_4)) { prefixedLogger.warn("Legacy is intended for Paper server versions 1.12 - 1.19.4."); - prefixedLogger.warn("Its highly recommended to use the Folia jar for your server."); + prefixedLogger.warn("Please use the Folia jar for your server to avoid issues due to old API calls."); + } + if (serverVersion.isOlderThanOrEquals(ServerVersion.V_1_12_2)) { + prefixedLogger.warn("This version is officially unsupported. Expect issues."); } try { - createDirectory(getDataFolder()); - } catch (IOException e) { - prefixedLogger.error("Unable to create plugin folder!", e); + Files.createDirectories(getDataFolder().toPath()); + } catch (Exception e) { + prefixedLogger.error("Unable to create plugin directory.", e); getServer().getPluginManager().disablePlugin(this); + return; } - prefixedLogger.info("Loading Datastore"); + instance = this; + + prefixedLogger.info("Registering Permissions"); + permissionHandler = PermissionHandler.create(this); + AEFPermission.registerAll(); + + prefixedLogger.info("Loading Data Storage"); datastore = new Datastore(); prefixedLogger.info("Loading Config"); @@ -143,29 +144,30 @@ public void onEnable() { prefixedLogger.info("Registering Commands"); AEFCommand.registerCommands(); - prefixedLogger.info("Registering Permissions"); - AEFPermission.registerPermissions(); + prefixedLogger.info("Loading NBT-API"); + // Hide all messages with a log level lower than WARNING because of the same reason as Reflections logging. + java.util.logging.Logger.getLogger("NBTAPI").setLevel(java.util.logging.Level.WARNING); + if (!NBT.preloadApi()) prefixedLogger.error("Error initializing NBT-API! This will break some modules!"); - prefixedLogger.info("Initializing PacketEvents"); - PacketEvents.getAPI().init(); + prefixedLogger.info("Loading Metrics"); + metrics = new Metrics(this, 8700); - prefixedLogger.info("Ready."); + prefixedLogger.info("Done."); } @Override public void onDisable() { + AEFPermission.unregisterAll(); if (isPacketEventsInstalled) { - AEFModule.ENABLED_MODULES.forEach(AEFModule::disable); - AEFModule.ENABLED_MODULES.clear(); - PacketEvents.getAPI().terminate(); + AEFModule.disableAll(); } if (languageCacheMap != null) { languageCacheMap.clear(); languageCacheMap = null; } - if (cachingPermTool != null) { - cachingPermTool.disable(); - cachingPermTool = null; + if (permissionHandler != null) { + permissionHandler.disable(); + permissionHandler = null; } if (tickReporter != null) { tickReporter.disable(); @@ -193,11 +195,15 @@ public static Config config() { return config; } - public static Datastore getDatastore() { + public static Datastore datastore() { return datastore; } - public static TickReporter getTickReporter() { + public static PermissionHandler permissions() { + return permissionHandler; + } + + public static TickReporter tickReporter() { return tickReporter; } @@ -222,14 +228,6 @@ public static LanguageCache getLang(String lang) { return languageCacheMap.getOrDefault(lang.replace("-", "_"), languageCacheMap.get(config.default_lang.toString().toLowerCase())); } - public void createDirectory(File dir) throws IOException { - try { - Files.createDirectories(dir.toPath()); - } catch (FileAlreadyExistsException e) { // Thrown if dir exists but is not a directory - if (dir.delete()) createDirectory(dir); - } - } - public void reloadPlugin() { reloadConfiguration(); reloadLang(); @@ -237,7 +235,6 @@ public void reloadPlugin() { private void reloadConfiguration() { try { - createDirectory(getDataFolder()); config = new Config(); if (tickReporter != null) tickReporter.disable(); tickReporter = TickReporter.create(this, config.tps_cache_duration); @@ -284,10 +281,9 @@ public void reloadLang() { private @NotNull List getAvailableTranslations() { try (final JarFile pluginJar = new JarFile(getFile())) { - createDirectory(new File(getDataFolder(), "/lang")); final Pattern langPattern = Pattern.compile("([a-z]{1,3}_[a-z]{1,3})(\\.yml)", Pattern.CASE_INSENSITIVE); - final File[] langDirFiles = new File(getDataFolder() + "/lang").listFiles(); - return Stream.concat(pluginJar.stream().map(ZipEntry::getName), Arrays.stream(langDirFiles).map(File::getName)) + final File langFolder = new File(getDataFolder(), "/lang"); + return (langFolder.exists() ? Arrays.stream(langFolder.listFiles()).map(File::getName) : pluginJar.stream().map(ZipEntry::getName)) .map(langPattern::matcher) .filter(Matcher::find) .map(matcher -> matcher.group(1)) diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/HelpCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/HelpCmd.java index 475252543..6635414fc 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/HelpCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/HelpCmd.java @@ -1,7 +1,7 @@ package me.xginko.aef.commands; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; @@ -36,7 +36,7 @@ public void enable() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_HELP.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_HELP.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/SayCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/SayCmd.java index ff98bfb60..cc1493c0f 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/SayCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/SayCmd.java @@ -1,7 +1,7 @@ package me.xginko.aef.commands; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.CommandUtil; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -38,7 +38,7 @@ public void enable() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_SAY.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_SAY.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java index aa6220141..91d399bd3 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java @@ -1,7 +1,7 @@ package me.xginko.aef.commands; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandException; @@ -39,7 +39,7 @@ public void enable() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_TOGGLE_CONNECT_MSGS.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_TOGGLE_CONNECT_MSGS.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } @@ -51,12 +51,12 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLab final Player player = (Player) sender; - AnarchyExploitFixes.getDatastore().getJoinLeaveEnabled(player.getUniqueId()).thenAccept(enabled -> { + AnarchyExploitFixes.datastore().getJoinLeaveEnabled(player.getUniqueId()).thenAccept(enabled -> { if (enabled) { - AnarchyExploitFixes.getDatastore().setJoinLeaveEnabled(player.getUniqueId(), false) + AnarchyExploitFixes.datastore().setJoinLeaveEnabled(player.getUniqueId(), false) .thenRun(() -> sender.sendMessage(AnarchyExploitFixes.getLang(player.getLocale()).misc_disabledConnectionMsgs)); } else { - AnarchyExploitFixes.getDatastore().setJoinLeaveEnabled(player.getUniqueId(), true) + AnarchyExploitFixes.datastore().setJoinLeaveEnabled(player.getUniqueId(), true) .thenRun(() -> sender.sendMessage(AnarchyExploitFixes.getLang(player.getLocale()).misc_enabledConnectionMsgs)); } }); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java index 8651e26ca..05441e07e 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java @@ -1,33 +1,32 @@ package me.xginko.aef.commands.aef; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.AEFCommand; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.commands.aef.subcommands.DataValueSubCmd; import me.xginko.aef.commands.aef.subcommands.DisableSubCmd; import me.xginko.aef.commands.aef.subcommands.ElytraSubCmd; import me.xginko.aef.commands.aef.subcommands.GearedSubCmd; import me.xginko.aef.commands.aef.subcommands.LagSubCmd; import me.xginko.aef.commands.aef.subcommands.ReloadSubCmd; import me.xginko.aef.commands.aef.subcommands.VersionSubCmd; -import me.xginko.aef.commands.aef.subcommands.bytesize.ByteSizeSubCmd; -import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; public class AEFCmd extends Command implements AEFCommand { - private final List subCommands; - private final List tabCompletes; - private final List overview; + private final Set subCommands; + private final List tabCompletes, overview; public AEFCmd() { super( @@ -38,30 +37,28 @@ public AEFCmd() { ); this.overview = Stream.of( "", - " &b&lAnarchyExploitFixes Commands", + " §b§lAnarchyExploitFixes Commands", "", - " &b/aef version &8- &fShow the plugin version.", - " &b/aef reload &8- &fReload the plugin.", - " &b/aef disable &8- &fDisable the plugin.", - " &b/aef lag &8- &fLag the server for testing.", - " &b/aef geared &8- &fCount how many players are wearing gear.", - " &b/aef elytra &8- &fCount how many players are flying elytra.", - " &b/aef datavalue &8- &fShow the MaterialData value of an item.", - " &b/aef bytesize (player) (utf8/utf16)", - " &8- &fGet the byte size of an item or inventory.", + " §b/aef version §8- §fShow the plugin version.", + " §b/aef reload §8- §fReload the plugin.", + " §b/aef disable §8- §fDisable the plugin.", + " §b/aef lag §8- §fLag the server for testing.", + " §b/aef geared §8- §fCount how many players are wearing gear.", + " §b/aef elytra §8- §fCount how many players are flying elytra.", + " §b/aef datavalue §8- §fShow the MaterialData value of an item.", + " §b/aef bytesize (player) (utf8/utf16)", + " §8- §fGet the byte size of an item or inventory.", "" - ).map(line -> ChatColor.translateAlternateColorCodes('&', line)).collect(Collectors.toList()); - this.subCommands = Arrays.asList( + ).collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf)); + this.subCommands = ImmutableSet.of( new ReloadSubCmd(), new VersionSubCmd(), new DisableSubCmd(), new LagSubCmd(), new ElytraSubCmd(), - new GearedSubCmd(), - new DataValueSubCmd(), - new ByteSizeSubCmd() - ); - this.tabCompletes = subCommands.stream().map(SubCommand::label).sorted().collect(Collectors.toList()); + new GearedSubCmd()); + this.tabCompletes = subCommands.stream().map(SubCommand::label).sorted() + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf)); } @Override @@ -80,7 +77,9 @@ public void enable() { throws CommandException, IllegalArgumentException { if (args.length == 1) { - return tabCompletes; + return tabCompletes.stream() + .filter(cmd -> cmd.toLowerCase(Locale.ROOT).startsWith(args[0].toLowerCase(Locale.ROOT))) + .collect(Collectors.toList()); } if (args.length > 1) { @@ -89,8 +88,6 @@ public void enable() { return subCommand.tabComplete(sender, alias, args); } } - - return tabCompletes.stream().filter(cmd -> cmd.startsWith(args[0])).collect(Collectors.toList()); } return Collections.emptyList(); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/DataValueSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/DataValueSubCmd.java index 785d3e517..12a3b28a6 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/DataValueSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/DataValueSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.ChatColor; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; @@ -29,7 +29,7 @@ public class DataValueSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_DISABLE.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_DATAVALUE.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/DisableSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/DisableSubCmd.java index 1d3e1cf5a..77e8f30a1 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/DisableSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/DisableSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import org.bukkit.ChatColor; import org.bukkit.command.CommandException; @@ -28,7 +28,7 @@ public class DisableSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_DISABLE.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_DISABLE.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } @@ -36,9 +36,8 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLab sender.sendMessage(""); sender.sendMessage(ChatColor.WHITE + " Disabling plugin."); AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getScheduler().runTask(plugin, () -> { - AEFModule.ENABLED_MODULES.forEach(AEFModule::disable); - AEFModule.ENABLED_MODULES.clear(); + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + AEFModule.disableAll(); sender.sendMessage(ChatColor.AQUA + " All enabled plugin features have been disabled."); sender.sendMessage(ChatColor.AQUA + " Use /aef reload to enable the plugin again."); sender.sendMessage(""); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/ElytraSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/ElytraSubCmd.java index d6e1efb12..5d7f4586c 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/ElytraSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/ElytraSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandException; @@ -30,7 +30,7 @@ public class ElytraSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_ELYTRA.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_ELYTRA.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/GearedSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/GearedSubCmd.java index 00ba01a69..caeef04d6 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/GearedSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/GearedSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandException; @@ -32,7 +32,7 @@ public class GearedSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_GEARED.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_GEARED.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/LagSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/LagSubCmd.java index 05d671885..74cdcf704 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/LagSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/LagSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.ChatColor; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; @@ -29,12 +29,16 @@ public LagSubCmd() { public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException { - return args.length == 2 && sender.hasPermission(AEFPermission.CMD_AEF_LAG.bukkit()) ? tabCompletes : Collections.emptyList(); + if (args.length == 2 && AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_LAG.node()).toBoolean()) { + return tabCompletes; + } + + return Collections.emptyList(); } @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_LAG.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_LAG.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/ReloadSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/ReloadSubCmd.java index 3bcf97e7d..b35464f89 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/ReloadSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/ReloadSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.ChatColor; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; @@ -27,7 +27,7 @@ public class ReloadSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_RELOAD.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_RELOAD.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } @@ -36,9 +36,9 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLab sender.sendMessage(""); sender.sendMessage(" Reloading AnarchyExploitFixes..."); - plugin.getServer().getScheduler().runTask(plugin, () -> { + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { plugin.reloadPlugin(); - sender.sendMessage(ChatColor.AQUA+" Reload complete."); + sender.sendMessage(ChatColor.AQUA + " Reload complete."); sender.sendMessage(""); }); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/VersionSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/VersionSubCmd.java index dd89c1f48..53838416c 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/VersionSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/VersionSubCmd.java @@ -2,7 +2,7 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.ChatColor; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; @@ -28,7 +28,7 @@ public class VersionSubCmd extends SubCommand { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_VERSION.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_VERSION.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ByteSizeSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ByteSizeSubCmd.java index 2dc889734..f3f9cd4f7 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ByteSizeSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ByteSizeSubCmd.java @@ -1,11 +1,11 @@ package me.xginko.aef.commands.aef.subcommands.bytesize; +import com.google.common.collect.ImmutableList; import me.xginko.aef.commands.SubCommand; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -16,8 +16,9 @@ public class ByteSizeSubCmd extends SubCommand { private final List tabCompletes; public ByteSizeSubCmd() { - this.subCommands = Arrays.asList(new InventorySubCmd(), new ItemSubCmd()); - this.tabCompletes = subCommands.stream().map(SubCommand::label).collect(Collectors.toList()); + this.subCommands = ImmutableList.of(new InventorySubCmd(), new ItemSubCmd()); + this.tabCompletes = subCommands.stream().map(SubCommand::label) + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf)); } @Override diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/InventorySubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/InventorySubCmd.java index f4d4a8532..6ec14f85b 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/InventorySubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/InventorySubCmd.java @@ -4,7 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -38,7 +38,7 @@ public InventorySubCmd() { public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException { - if (!sender.hasPermission(AEFPermission.CMD_AEF_SIZE_INV.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_SIZE_INV.node()).toBoolean()) { return Collections.emptyList(); } @@ -61,7 +61,7 @@ public InventorySubCmd() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_SIZE_INV.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_SIZE_INV.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ItemSubCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ItemSubCmd.java index 469675096..c25adf132 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ItemSubCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/subcommands/bytesize/ItemSubCmd.java @@ -4,7 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.SubCommand; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -38,7 +38,7 @@ public ItemSubCmd() { public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException { - if (!sender.hasPermission(AEFPermission.CMD_AEF_SIZE_HAND.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_SIZE_HAND.node()).toBoolean()) { return Collections.emptyList(); } @@ -61,7 +61,7 @@ public ItemSubCmd() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { - if (!sender.hasPermission(AEFPermission.CMD_AEF_SIZE_HAND.bukkit())) { + if (!AnarchyExploitFixes.permissions().permissionValue(sender, AEFPermission.CMD_AEF_SIZE_HAND.node()).toBoolean()) { sender.sendMessage(AnarchyExploitFixes.getLang(sender).no_permission); return true; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/Config.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/Config.java index 2fcf27443..d6537e092 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/Config.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/Config.java @@ -37,6 +37,7 @@ public Config() throws Exception { AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); // Load config.yml with ConfigMaster this.config = ConfigFile.loadConfig(new File(plugin.getDataFolder(), "config.yml")); + config.set("plugin-version", plugin.getDescription().getVersion()); config.set("server-version", plugin.getServer().getVersion()); @@ -112,14 +113,10 @@ public Config() throws Exception { "Plays XP pickup sound to alert players when theyre going\n" + "above the limit."); String configuredSound = getString("elytra.elytra-speed.sound", XSound.ENTITY_EXPERIENCE_ORB_PICKUP.name()); - Sound parsedSound; - try { - parsedSound = XSound.valueOf(configuredSound).parseSound(); - } catch (IllegalArgumentException e) { - AnarchyExploitFixes.prefixedLogger().warn(" Sound '"+configuredSound+"' does not exist in XSound. Using default."); - parsedSound = XSound.ENTITY_EXPERIENCE_ORB_PICKUP.parseSound(); - } - this.elytra_too_fast_sound = parsedSound; + this.elytra_too_fast_sound = XSound.of(configuredSound).orElseGet(() -> { + AnarchyExploitFixes.prefixedLogger().warn(" Sound '{}' does not exist in XSound. Using default.", configuredSound); + return XSound.ENTITY_EXPERIENCE_ORB_PICKUP; + }).get(); this.elytra_teleport_back = getBoolean("elytra.elytra-speed.teleport-instead-of-canceling-movement", false, "Recommended to leave false if you dont experience any issues."); this.elytra_enable_global = getBoolean("elytra.elytra-speed.Global-Settings.enable", true); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/Datastore.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/Datastore.java index 54de6df07..28b35f4e8 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/Datastore.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/Datastore.java @@ -4,6 +4,8 @@ import com.zaxxer.hikari.HikariDataSource; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.utils.models.Disableable; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configurator; import javax.sql.DataSource; import java.sql.Connection; @@ -19,6 +21,16 @@ public class Datastore implements Disableable { private final DataSource dataSource; private final String loadPlayer, savePlayerConMsgSetting; + static { + // Disable logging because hikari is VERY verbose + String hikariShaded = AnarchyExploitFixes.class.getPackage().getName() + ".libs.zaxxer.hikari"; + Configurator.setLevel(hikariShaded + ".pool.PoolBase", Level.OFF); + Configurator.setLevel(hikariShaded + ".pool.HikariPool", Level.OFF); + Configurator.setLevel(hikariShaded + ".HikariDataSource", Level.OFF); + Configurator.setLevel(hikariShaded + ".HikariConfig", Level.OFF); + Configurator.setLevel(hikariShaded + ".util.DriverDataSource", Level.OFF); + } + public Datastore() { HikariConfig config = new HikariConfig(); AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/LanguageCache.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/LanguageCache.java index 59bc0823d..f68e7a2b3 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/LanguageCache.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/config/LanguageCache.java @@ -5,6 +5,7 @@ import org.bukkit.ChatColor; import java.io.File; +import java.nio.file.Files; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -33,9 +34,9 @@ public LanguageCache(String langString) throws Exception { AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); File langYML = new File(plugin.getDataFolder() + "/lang", langString + ".yml"); // Check if the lang folder has already been created - File parent = langYML.getParentFile(); - if (!parent.exists() && !parent.mkdir()) - AnarchyExploitFixes.prefixedLogger().error("Unable to create lang directory."); + File langFolder = langYML.getParentFile(); + if (!langFolder.exists()) + Files.createDirectories(langFolder.toPath()); // Check if the file already exists and save the one from the plugin's resources folder if it does not if (!langYML.exists()) plugin.saveResource("lang/" + langString + ".yml", false); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/AEFModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/AEFModule.java index 092826bb8..c9a86640e 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/AEFModule.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/AEFModule.java @@ -1,5 +1,6 @@ package me.xginko.aef.modules; +import com.google.common.collect.ImmutableSet; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.config.Config; import me.xginko.aef.modules.packets.PacketModule; @@ -9,52 +10,101 @@ import org.reflections.scanners.Scanners; import java.lang.reflect.Modifier; +import java.util.Comparator; import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; public abstract class AEFModule implements ConditionalEnableable, Disableable { - private static final Reflections MODULES_PACKAGE = new Reflections(AEFModule.class.getPackage().getName()); - public static final Set ENABLED_MODULES = new HashSet<>(); + protected static final Set> AVAILABLE_MODULES; + protected static final Set ENABLED_MODULES; - protected final AnarchyExploitFixes plugin; - protected final Config config; - public final String configPath; - private final String logFormat; + static { + AVAILABLE_MODULES = new Reflections(AEFModule.class.getPackage().getName()) + .get(Scanners.SubTypes.of(AEFModule.class).asClass()) + .stream() + .filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) + .map(clazz -> (Class) clazz) + .sorted(Comparator.comparing(Class::getSimpleName)) + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableSet::copyOf)); + ENABLED_MODULES = new HashSet<>(); + } + + protected final AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); + protected final Config config = AnarchyExploitFixes.config(); - public AEFModule(String configPath) { - this.plugin = AnarchyExploitFixes.getInstance(); - this.config = AnarchyExploitFixes.config(); + protected final String configPath, logFormat; + protected final boolean configEnabled; + + public AEFModule(String configPath) { // Modules that should not automatically get an enable option this.configPath = configPath; - shouldEnable(); // Ensure enable option is always first - String[] paths = configPath.split("\\."); - if (paths.length <= 2) { - this.logFormat = "<" + configPath + "> {}"; + this.configEnabled = false; + this.logFormat = createLogFormat(configPath); + } + + public AEFModule(String configPath, boolean defEnabled) { + this(configPath, defEnabled, null); + } + + public AEFModule(String configPath, boolean defEnabled, String comment) { + this.configPath = configPath; + this.logFormat = createLogFormat(configPath); + if (comment == null || comment.isEmpty()) { + this.configEnabled = config.getBoolean(configPath + ".enable", defEnabled); } else { - this.logFormat = "<" + paths[paths.length - 2] + "." + paths[paths.length - 1] + "> {}"; + this.configEnabled = config.getBoolean(configPath + ".enable", defEnabled, comment); } } - public static void reloadModules() { - ENABLED_MODULES.forEach(AEFModule::disable); + private static String createLogFormat(String configPath) { + String[] paths = configPath.split("\\."); + return "<" + (paths.length < 3 ? configPath : paths[paths.length - 2] + "." + paths[paths.length - 1]) + "> {}"; + } + + public boolean shouldEnable() { + return configEnabled; + } + + public static void disableAll() { + for (AEFModule module : ENABLED_MODULES) { + try { + module.disable(); + } catch (Throwable t) { + module.error("Failed during disable. " + t.getLocalizedMessage()); + } + } ENABLED_MODULES.clear(); + } - for (Class clazz : MODULES_PACKAGE.get(Scanners.SubTypes.of(AEFModule.class).asClass())) { - if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) continue; + public static void reloadModules() { + disableAll(); + for (Class moduleClass : AVAILABLE_MODULES) { try { - AEFModule module = (AEFModule) clazz.getDeclaredConstructor().newInstance(); + AEFModule module = moduleClass.getDeclaredConstructor().newInstance(); if (module.shouldEnable()) { if (module instanceof PacketModule && AnarchyExploitFixes.config().packets_disabled) { module.warn("Cannot enable because you disabled packets in config!"); - continue; + } else { + ENABLED_MODULES.add(module); } - - module.enable(); - ENABLED_MODULES.add(module); } } catch (Throwable t) { - AnarchyExploitFixes.prefixedLogger().error("Failed to load module {}", clazz.getSimpleName(), t); + if (t.getCause() instanceof NoClassDefFoundError) { + AnarchyExploitFixes.prefixedLogger().info("Dependencies for module class {} missing, cannot enable.", moduleClass.getSimpleName()); + } else { + AnarchyExploitFixes.prefixedLogger().warn("Module class '{}' failed to init.", moduleClass.getSimpleName(), t); + } + } + } + + for (AEFModule module : ENABLED_MODULES) { + try { + module.enable(); + } catch (Throwable t) { + module.error("Failed during enable. " + t.getLocalizedMessage()); + try { module.disable(); } catch (Throwable ignored) {} } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillNetherCeilingOnChunkload.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillNetherCeilingOnChunkload.java index 1056a7f80..f0f75addf 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillNetherCeilingOnChunkload.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillNetherCeilingOnChunkload.java @@ -21,7 +21,7 @@ public class FillNetherCeilingOnChunkload extends AEFModule implements Listener private final boolean alsoCheckNewChunks, pauseOnLowTPS; public FillNetherCeilingOnChunkload() { - super("bedrock.fill-in-bedrock.nether-ceiling.fill-on-chunkload"); + super("bedrock.fill-in-bedrock.nether-ceiling.fill-on-chunkload", false); this.alsoCheckNewChunks = config.getBoolean(configPath + ".also-check-new-chunks", false, "Recommended to leave off. Only useful if world generation is broken."); this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", @@ -38,11 +38,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -50,12 +45,12 @@ public void disable() { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; if (!alsoCheckNewChunks && event.isNewChunk()) return; - final World world = event.getWorld(); - if (world.getEnvironment() != World.Environment.NETHER) return; - if (exemptedWorlds.contains(world.getName())) return; + if (event.getWorld().getEnvironment() != World.Environment.NETHER) return; + if (exemptedWorlds.contains(event.getWorld().getName())) return; - if (!pauseOnLowTPS || AnarchyExploitFixes.getTickReporter().getTPS() >= pauseTPS) { + if (!pauseOnLowTPS || AnarchyExploitFixes.tickReporter().getTPS() >= pauseTPS) { ChunkUtil.createBedrockLayer(event.getChunk(), config.nether_ceiling_max_y); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillNetherFloorOnChunkload.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillNetherFloorOnChunkload.java index c35372c01..197621018 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillNetherFloorOnChunkload.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillNetherFloorOnChunkload.java @@ -22,7 +22,7 @@ public class FillNetherFloorOnChunkload extends AEFModule implements Listener { private final boolean alsoCheckNewChunks, pauseOnLowTPS; public FillNetherFloorOnChunkload() { - super("bedrock.fill-in-bedrock.nether-floor.fill-on-chunkload"); + super("bedrock.fill-in-bedrock.nether-floor.fill-on-chunkload", false); this.alsoCheckNewChunks = config.getBoolean(configPath + ".also-check-new-chunks", false, "Recommended to leave off. Only useful if world generation is broken."); this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", @@ -38,11 +38,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -50,13 +45,13 @@ public void disable() { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { - final World world = event.getWorld(); - if (world.getEnvironment() != World.Environment.NETHER) return; - if (exemptedWorlds.contains(world.getName())) return; + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; if (!alsoCheckNewChunks && event.isNewChunk()) return; + if (event.getWorld().getEnvironment() != World.Environment.NETHER) return; + if (exemptedWorlds.contains(event.getWorld().getName())) return; - if (!pauseOnLowTPS || AnarchyExploitFixes.getTickReporter().getTPS() >= pauseTPS) { - ChunkUtil.createBedrockLayer(event.getChunk(), WorldUtil.getMinWorldHeight(world)); + if (!pauseOnLowTPS || AnarchyExploitFixes.tickReporter().getTPS() >= pauseTPS) { + ChunkUtil.createBedrockLayer(event.getChunk(), WorldUtil.getMinWorldHeight(event.getWorld())); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillOverworldFloorOnChunkload.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillOverworldFloorOnChunkload.java index 13e9613eb..16ef3fa9f 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillOverworldFloorOnChunkload.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/FillOverworldFloorOnChunkload.java @@ -22,7 +22,7 @@ public class FillOverworldFloorOnChunkload extends AEFModule implements Listener private final boolean alsoCheckNewChunks, pauseOnLowTPS; public FillOverworldFloorOnChunkload() { - super("bedrock.fill-in-bedrock.overworld-floor.fill-on-chunkload"); + super("bedrock.fill-in-bedrock.overworld-floor.fill-on-chunkload", false); this.alsoCheckNewChunks = config.getBoolean(configPath + ".also-check-new-chunks", false, "Recommended to leave off. Only useful if world generation is broken."); this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", @@ -38,11 +38,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -50,13 +45,13 @@ public void disable() { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; if (!alsoCheckNewChunks && event.isNewChunk()) return; - final World world = event.getWorld(); - if (world.getEnvironment() != World.Environment.NORMAL) return; - if (exemptedWorlds.contains(world.getName())) return; + if (event.getWorld().getEnvironment() != World.Environment.NORMAL) return; + if (exemptedWorlds.contains(event.getWorld().getName())) return; - if (!pauseOnLowTPS || AnarchyExploitFixes.getTickReporter().getTPS() >= pauseTPS) { - ChunkUtil.createBedrockLayer(event.getChunk(), WorldUtil.getMinWorldHeight(world)); + if (!pauseOnLowTPS || AnarchyExploitFixes.tickReporter().getTPS() >= pauseTPS) { + ChunkUtil.createBedrockLayer(event.getChunk(), WorldUtil.getMinWorldHeight(event.getWorld())); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherCeiling.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherCeiling.java index 6fffbeb59..bdce04d4f 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherCeiling.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherCeiling.java @@ -17,11 +17,12 @@ public class PeriodicallyFillNetherCeiling extends AEFModule implements Runnable private final long checkPeriod; private final double pauseTPS; private final boolean checkShouldPauseOnLowTPS; + private BukkitTask bukkitTask; public PeriodicallyFillNetherCeiling() { - super("bedrock.fill-in-bedrock.nether-ceiling.periodically-check-and-fill"); - config.addComment(configPath + ".enable","Only checks loaded chunks."); + super("bedrock.fill-in-bedrock.nether-ceiling.periodically-check-and-fill", false, + "Only checks loaded chunks."); this.checkPeriod = config.getInt(configPath + ".check-period-in-seconds", 10) * 20L; this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", Arrays.asList("exampleworld", "exampleworld2"), @@ -36,24 +37,24 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, 20L, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @Override public void run() { - if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; for (World world : plugin.getServer().getWorlds()) { if (world.getEnvironment() == World.Environment.NETHER) { if (!exemptedWorlds.contains(world.getName())) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + ChunkUtil.createBedrockLayer(chunk, config.nether_ceiling_max_y); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherFloor.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherFloor.java index 5117f34b2..13ad78017 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherFloor.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillNetherFloor.java @@ -18,10 +18,11 @@ public class PeriodicallyFillNetherFloor extends AEFModule implements Runnable { private final long checkPeriod; private final double pauseTPS; private final boolean checkShouldPauseOnLowTPS; + private BukkitTask bukkitTask; public PeriodicallyFillNetherFloor() { - super("bedrock.fill-in-bedrock.nether-floor.periodically-check-and-fill"); + super("bedrock.fill-in-bedrock.nether-floor.periodically-check-and-fill", false); config.addComment(configPath + ".enable","Only checks loaded chunks."); this.checkPeriod = config.getInt(configPath + ".check-period-in-seconds", 10) * 20L; this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", @@ -37,24 +38,24 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, 20L, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @Override public void run() { - if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; for (World world : plugin.getServer().getWorlds()) { if (world.getEnvironment() == World.Environment.NETHER) { if (!exemptedWorlds.contains(world.getName())) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + ChunkUtil.createBedrockLayer(chunk, WorldUtil.getMinWorldHeight(world)); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillOverworldFloor.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillOverworldFloor.java index 06b61e5d3..ce9fff976 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillOverworldFloor.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PeriodicallyFillOverworldFloor.java @@ -18,11 +18,12 @@ public class PeriodicallyFillOverworldFloor extends AEFModule implements Runnabl private final long checkPeriod; private final double pauseTPS; private final boolean checkShouldPauseOnLowTPS; + private BukkitTask bukkitTask; public PeriodicallyFillOverworldFloor() { - super("bedrock.fill-in-bedrock.overworld-floor.periodically-check-and-fill"); - config.addComment(configPath + ".enable","only checks loaded chunks"); + super("bedrock.fill-in-bedrock.overworld-floor.periodically-check-and-fill", false, + "Only checks loaded chunks"); this.checkPeriod = config.getInt(configPath + ".check-period-in-seconds", 10) * 20L; this.exemptedWorlds = new HashSet<>(config.getList(configPath + ".exempted-worlds", Arrays.asList("exampleworld", "exampleworld2"), @@ -37,24 +38,24 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, 20L, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @Override public void run() { - if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; for (World world : plugin.getServer().getWorlds()) { if (world.getEnvironment() == World.Environment.NORMAL) { if (!exemptedWorlds.contains(world.getName())) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + ChunkUtil.createBedrockLayer(chunk, WorldUtil.getMinWorldHeight(world)); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PreventGoingBelowBedrockFloor.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PreventGoingBelowBedrockFloor.java index 440caf3f5..facc82d31 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PreventGoingBelowBedrockFloor.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/bedrock/PreventGoingBelowBedrockFloor.java @@ -5,7 +5,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; @@ -24,7 +23,7 @@ public class PreventGoingBelowBedrockFloor extends AEFModule implements Listener private final double damageOnMove; public PreventGoingBelowBedrockFloor() { - super("bedrock.prevent-going-below-bedrock-floor"); + super("bedrock.prevent-going-below-bedrock-floor", true); config.addComment(configPath + ".enable", "Prevents players from going below the bedrock floor."); this.vehicleEject = config.getBoolean(configPath + ".eject-player", true, @@ -54,11 +53,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -66,18 +60,17 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { - final Player player = event.getPlayer(); - final World world = player.getWorld(); + final World world = event.getPlayer().getWorld(); if (exemptedWorlds.contains(world.getName())) return; - final Location playerLoc = player.getLocation(); + final Location playerLoc = event.getPlayer().getLocation(); if (playerLoc.getY() >= WorldUtil.getMinWorldHeight(world)) return; - if (vehicleEject && player.getVehicle() != null) { - player.getVehicle().eject(); + if (vehicleEject && event.getPlayer().getVehicle() != null) { + event.getPlayer().getVehicle().eject(); } - if (closeElytra && player.isGliding()) { - player.setGliding(false); + if (closeElytra && event.getPlayer().isGliding()) { + event.getPlayer().setGliding(false); } if (fillHole) { @@ -90,13 +83,13 @@ private void onPlayerMove(PlayerMoveEvent event) { // Teleport player up, so he lands on top of that bedrock Location threeBlocksUp = event.getFrom().clone().add(0, 3, 0); event.setTo(threeBlocksUp); - player.teleport(threeBlocksUp); + event.getPlayer().teleport(threeBlocksUp); } if (damageOnMove > 0) { // Deal damage when moving below bedrock. Just in case everything else fails // to prevent players from moving below bedrock. - player.damage(damageOnMove); + event.getPlayer().damage(damageOnMove); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chat/PreventPluginScanning.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chat/PreventPluginScanning.java index ca7672f52..5c96ec9dd 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chat/PreventPluginScanning.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chat/PreventPluginScanning.java @@ -1,7 +1,8 @@ package me.xginko.aef.modules.chat; import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.AnarchyExploitFixes; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -16,11 +17,10 @@ public class PreventPluginScanning extends AEFModule implements Listener { public PreventPluginScanning() { - super("chat.prevent-scanning-server-plugins"); - config.addComment(configPath + ".enable", + super("chat.prevent-scanning-server-plugins", true, "Prevents hacked clients running .plugins to find out what plugins\n" + - "the server is using.\n" + - "Recommended to use in combination with command whitelist."); + "the server is using.\n" + + "Recommended to use in combination with command whitelist."); } @Override @@ -28,11 +28,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -44,7 +39,7 @@ private boolean isSuspectedScanPacket(String buffer) { @EventHandler(priority = EventPriority.HIGHEST) private void onAsyncCommandTabComplete(AsyncTabCompleteEvent event) { - if (event.getSender().hasPermission(AEFPermission.BYPASS_CHAT.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getSender(), AEFPermission.BYPASS_CHAT.node()).toBoolean()) return; if (isSuspectedScanPacket(event.getBuffer())) { event.setCancelled(true); @@ -53,7 +48,7 @@ private void onAsyncCommandTabComplete(AsyncTabCompleteEvent event) { @EventHandler(priority = EventPriority.HIGHEST) private void onCommandTabComplete(TabCompleteEvent event) { - if (event.getSender().hasPermission(AEFPermission.BYPASS_CHAT.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getSender(), AEFPermission.BYPASS_CHAT.node()).toBoolean()) return; if (isSuspectedScanPacket(event.getBuffer())) { event.setCancelled(true); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CommandWhitelist.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CommandWhitelist.java index 4754a75d5..b9cd06bc3 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CommandWhitelist.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CommandWhitelist.java @@ -12,7 +12,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientTabComplete; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTabComplete; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.CommandUtil; import org.bukkit.entity.Player; @@ -35,17 +35,17 @@ */ public class CommandWhitelist extends AEFModule implements PacketListener, Listener { - private final PacketListenerAbstract abstractListener; - private Listener commandSendListener; private final Set allowedCommands, bannedSubCommands; private final boolean usePackets, shouldLog; + private PacketListenerAbstract packetListenerAbstract; + private Listener commandSendListener; + public CommandWhitelist() { - super("chat.command-whitelist"); - config.addComment(configPath + ".enable", + super("chat.command-whitelist", false, "This will make it pretty much impossible to find your plugins as\n" + - "only the commands you specify will be able to work.\n" + - "Allow bypass using permission: " + AEFPermission.BYPASS_CMD_WHITELIST.string()); + "only the commands you specify will be able to work.\n" + + "Allow bypass using permission: " + AEFPermission.BYPASS_CMD_WHITELIST.node()); this.shouldLog = config.getBoolean(configPath + ".log", false, "Will show logs when a command was denied."); this.usePackets = config.getBoolean(configPath + ".use-packets", true, @@ -56,7 +56,7 @@ public CommandWhitelist() { "toggledeathmsg", "dmt", "worldstats", "stats", "tps", "msg", "whisper", "w", "m", "t", "pm", "tell", "r", "reply", "last"), "Add all commands you WANT your players to be able to access\n" + - "WITHOUT the '/'. Not case sensitive.") + "WITHOUT the '/'. Not case sensitive.") .stream() .map(String::toLowerCase) .collect(Collectors.toCollection(HashSet::new)); @@ -64,46 +64,47 @@ public CommandWhitelist() { Arrays.asList("help about", "vote List", "vote Best", "vote Total", "worldstats reload", "stats reload"), "Add all subcommands you DON'T want your players to be able\n" + "to access. Case sensitive!")); - if (CWCommandSendListener.isSupported()) // Not available by default on 1.12 - this.commandSendListener = new CWCommandSendListener(allowedCommands); - this.abstractListener = asAbstract(PacketListenerPriority.HIGHEST); } @Override public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); - if (commandSendListener != null) + if (CWCommandSendListener.isSupported()) { // Legacy versions do not have this event + commandSendListener = new CWCommandSendListener(allowedCommands); plugin.getServer().getPluginManager().registerEvents(commandSendListener, plugin); + } if (usePackets) { if (AnarchyExploitFixes.config().packets_disabled) { warn("Can't enable packet listener because packet events is disabled in config."); } else { - PacketEvents.getAPI().getEventManager().registerListener(abstractListener); + packetListenerAbstract = asAbstract(PacketListenerPriority.HIGHEST); + PacketEvents.getAPI().getEventManager().registerListener(packetListenerAbstract); } } } - @Override - public boolean shouldEnable() { - return AnarchyExploitFixes.config().getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (commandSendListener != null) + if (commandSendListener != null) { HandlerList.unregisterAll(commandSendListener); - PacketEvents.getAPI().getEventManager().unregisterListener(abstractListener); + commandSendListener = null; + } + if (packetListenerAbstract != null) { + PacketEvents.getAPI().getEventManager().unregisterListener(packetListenerAbstract); + packetListenerAbstract = null; + } } @Override public void onPacketReceive(PacketReceiveEvent event) { if (event.isCancelled()) return; + if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE) { if (CWCommandSendListener.isSupported()) return; - final Player player = (Player) event.getPlayer(); - if (player != null && player.hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + final Player player = event.getPlayer(); + if (player != null && AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; String text = new WrapperPlayClientTabComplete(event).getText(); if (!text.startsWith("/")) return; // We only care about the initial command, everything else is handled by the API @@ -143,8 +144,8 @@ else if (allowedCommand.startsWith(text.substring(1))) { return; } - final Player player = (Player) event.getPlayer(); - if (player != null && player.hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + final Player player = event.getPlayer(); + if (player != null && AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; if (!allowedCommands.contains(CommandUtil.getCommandLabel(message).toLowerCase())) { event.setCancelled(true); @@ -166,7 +167,7 @@ else if (allowedCommand.startsWith(text.substring(1))) { @EventHandler(priority = EventPriority.HIGHEST) private void onCommandPreProcess(PlayerCommandPreprocessEvent event) { final Player player = event.getPlayer(); - if (player.hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; String message = event.getMessage(); String commandLabel = CommandUtil.getCommandLabel(message).toLowerCase(); @@ -194,8 +195,7 @@ private void onCommandPreProcess(PlayerCommandPreprocessEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onAsyncCommandTabComplete(AsyncTabCompleteEvent event) { if (event.getCompletions().isEmpty()) return; - if (!(event.getSender() instanceof Player)) return; - if (event.getSender().hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getSender(), AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; event.setCompletions(getFilteredTabCompletions(event.getBuffer(), event.getCompletions())); } @@ -203,8 +203,7 @@ private void onAsyncCommandTabComplete(AsyncTabCompleteEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onCommandTabComplete(TabCompleteEvent event) { if (event.getCompletions().isEmpty()) return; - if (!(event.getSender() instanceof Player)) return; - if (event.getSender().hasPermission(AEFPermission.BYPASS_CMD_WHITELIST.bukkit())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getSender(), AEFPermission.BYPASS_CMD_WHITELIST.node()).toBoolean()) return; event.setCompletions(getFilteredTabCompletions(event.getBuffer(), event.getCompletions())); } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/BlockLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/BlockLimit.java index bf633d78a..590eda3f3 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/BlockLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/BlockLimit.java @@ -1,6 +1,8 @@ package me.xginko.aef.modules.chunklimits; import com.cryptomorin.xseries.XMaterial; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.WorldUtil; @@ -10,8 +12,11 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import java.time.Duration; import java.util.EnumMap; import java.util.Map; import java.util.TreeMap; @@ -19,9 +24,14 @@ public class BlockLimit extends AEFModule implements Listener { private final Map blockLimits = new EnumMap<>(Material.class); + private final long materialCountCacheMillis; + + private Cache> chunkMaterialCache; public BlockLimit() { - super("chunk-limits.block-limit"); + super("chunk-limits.block-limit", false); + this.materialCountCacheMillis = config.getLong(configPath + ".material-count-cache-millis", 1000, + "Recommended to not go higher than 5000ms."); Map universal = new EnumMap<>(XMaterial.class); universal.put(XMaterial.ENCHANTING_TABLE, 16); @@ -123,7 +133,7 @@ public BlockLimit() { Map compatible = new TreeMap<>(); for (Map.Entry entry : universal.entrySet()) { if (entry.getKey().isSupported()) { - compatible.put(entry.getKey().parseMaterial().name(), entry.getValue()); + compatible.put(entry.getKey().get().name(), entry.getValue()); } } @@ -144,44 +154,70 @@ public BlockLimit() { @Override public void enable() { + chunkMaterialCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(1)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (chunkMaterialCache != null) { + for (Map.Entry> entry : chunkMaterialCache.asMap().entrySet()) { + entry.getValue().invalidateAll(); + entry.getValue().cleanUp(); + } + chunkMaterialCache.invalidateAll(); + chunkMaterialCache.cleanUp(); + chunkMaterialCache = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPlace(BlockPlaceEvent event) { - final Material placedType = event.getBlock().getType(); - if ( - blockLimits.containsKey(placedType) - && exceedsPerChunkLimit(placedType, blockLimits.get(placedType), event.getBlock().getChunk()) - ) { + if (blockLimits.containsKey(event.getBlock().getType()) + && exceedsPerChunkLimit(event.getBlock().getType(), event.getBlock().getChunk())) { event.setCancelled(true); } } - private boolean exceedsPerChunkLimit(Material material, int limit, Chunk chunk) { + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPlayerInteract(PlayerInteractEvent event) { + if (event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) return; + + if (blockLimits.containsKey(event.getMaterial()) + && exceedsPerChunkLimit(event.getMaterial(), event.getPlayer().getChunk())) { + event.setCancelled(true); + } + } + + private boolean exceedsPerChunkLimit(Material blockType, Chunk chunk) { + final int limit = blockLimits.get(blockType); final int minY = WorldUtil.getMinWorldHeight(chunk.getWorld()); final int maxY = chunk.getWorld().getMaxHeight(); - int count = 0; - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = minY; y < maxY; y++) { - if (chunk.getBlock(x, y, z).getType() == material) { - count++; - if (count > limit) return true; + + Cache exceededCache = chunkMaterialCache.getIfPresent(chunk); + if (exceededCache == null) { + exceededCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(materialCountCacheMillis)).build(); + } + + Boolean exceeded = exceededCache.get(blockType, material -> { + int count = 0; + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = minY; y < maxY; y++) { + if (chunk.getBlock(x, y, z).getType() == material) { + count++; + if (count > limit) { + return true; + } + } } } } - } - return false; + return false; + }); + + chunkMaterialCache.put(chunk, exceededCache); + return exceeded; } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/CustomEntityLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/CustomEntityLimit.java index 6d44e7626..64d20cbbe 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/CustomEntityLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/CustomEntityLimit.java @@ -3,6 +3,7 @@ import com.cryptomorin.xseries.XEntityType; import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; import org.bukkit.Material; @@ -26,11 +27,13 @@ public class CustomEntityLimit extends AEFModule implements Runnable, Listener { private final Map entityLimits = new EnumMap<>(EntityType.class); private final long checkPeriod; private final boolean logIsEnabled; + private BukkitTask bukkitTask; public CustomEntityLimit() { - super("chunk-limits.entity-limits.custom-limit"); - config.addComment(configPath + ".enable", "Limit specific entity types per chunk."); + super("chunk-limits.entity-limits.custom-limit", false, + "Limit specific entity types per chunk.\n" + + "Read over the defaults at least once before enabling."); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", true); this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 1200, "Check all loaded chunks every x ticks."); @@ -141,19 +144,19 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChunkUnload(ChunkUnloadEvent event) { + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; + for (Map.Entry limit : entityLimits.entrySet()) { final int maxAllowedPerChunk = limit.getValue(); int entityCount = 0; @@ -173,14 +176,13 @@ private void onChunkUnload(ChunkUnloadEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onSpawn(EntitySpawnEvent event) { - EntityType spawnedType = event.getEntityType(); - if (!entityLimits.containsKey(spawnedType)) return; + if (!entityLimits.containsKey(event.getEntityType())) return; - final int maxAllowedPerChunk = entityLimits.get(spawnedType); + final int maxAllowedPerChunk = entityLimits.get(event.getEntityType()); int entityCount = 0; for (Entity entity : event.getEntity().getChunk().getEntities()) { - if (entity.getType() != spawnedType) continue; + if (entity.getType() != event.getEntityType()) continue; entityCount++; if (entityCount <= maxAllowedPerChunk) continue; @@ -195,6 +197,7 @@ private void onSpawn(EntitySpawnEvent event) { public void run() { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; if (!chunk.isLoaded()) continue; Entity[] chunkEntities = chunk.getEntities(); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java index ac4a1f31e..b6858f36a 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java @@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.MaterialUtil; import me.xginko.aef.utils.models.ChunkUID; @@ -22,26 +23,27 @@ import java.time.Duration; import java.util.EnumSet; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; public class DroppedItemLimit extends AEFModule implements Listener, Runnable { - private final Cache scheduledChecks; private final Set whitelistedTypes; private final long checkPeriod, cleanupDelay; private final int maxDroppedItemsPerChunk; private final boolean logIsEnabled, usingWhitelist, onChunkLoad; + + private Cache scheduledChecks; private BukkitTask bukkitTask; public DroppedItemLimit() { - super("chunk-limits.entity-limits.dropped-item-limit"); - config.addComment(configPath + ".enable", + super("chunk-limits.entity-limits.dropped-item-limit", false, "Limit the amount of dropped items in a chunk to combat lag.\n" + - "Be aware this does not prioritize items by value or anything,\n" + - "it just deletes whatever happens to get over the limit during\n" + - "counting."); + "Be aware this does not prioritize items by value or anything,\n" + + "it just deletes whatever happens to get over the limit during\n" + + "counting."); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", true); this.maxDroppedItemsPerChunk = config.getInt(configPath + ".max-dropped-items-per-chunk", 200); this.cleanupDelay = Math.max(1, config.getInt(configPath + ".post-item-drop-check-delay", 60, @@ -49,7 +51,6 @@ public DroppedItemLimit() { "has dropped before the check logic will run.\n" + "This improves performance as there will be no check for each single\n" + "item entity that spawns.")); - this.scheduledChecks = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cleanupDelay * 50L)).build(); this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 1200, "The period in ticks in which all loaded chunks should be regularly\n" + "checked. Keep in mind: A lower number provides more accuracy but is\n" + @@ -77,19 +78,27 @@ public DroppedItemLimit() { @Override public void enable() { + scheduledChecks = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cleanupDelay * 50L)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); - bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); + bukkitTask = plugin.getServer().getScheduler() + .runTaskTimer(plugin, this, checkPeriod, checkPeriod); } @Override public void disable() { HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } + if (scheduledChecks != null) { + for (Map.Entry entry : scheduledChecks.asMap().entrySet()) { + entry.getValue().cancel(); + } + scheduledChecks.invalidateAll(); + scheduledChecks.cleanUp(); + scheduledChecks = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -98,7 +107,7 @@ private void onItemDrop(ItemSpawnEvent event) { final ChunkUID chunkUID = ChunkUID.of(chunk); // Don't create a check task for each spawning item scheduledChecks.get(chunkUID, k -> - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> { + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { if (!chunk.isLoaded()) return; int droppedItemCount = 0; @@ -121,6 +130,7 @@ private void onItemDrop(ItemSpawnEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { if (!onChunkLoad || event.isNewChunk()) return; + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; int droppedItemCount = 0; @@ -141,6 +151,7 @@ private void onChunkLoad(ChunkLoadEvent event) { public void run() { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; if (!chunk.isLoaded()) continue; int droppedItemCount = 0; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/ExpBottleLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/ExpBottleLimit.java deleted file mode 100755 index 171d42eba..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/ExpBottleLimit.java +++ /dev/null @@ -1,90 +0,0 @@ -package me.xginko.aef.modules.chunklimits; - -import com.cryptomorin.xseries.XEntityType; -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.LocationUtil; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.ExpBottleEvent; -import org.bukkit.scheduler.BukkitTask; - -public class ExpBottleLimit extends AEFModule implements Runnable, Listener { - - private final long checkPeriod; - private final int maxExpBottlePerChunk; - private final boolean logIsEnabled; - private BukkitTask bukkitTask; - - public ExpBottleLimit() { - super("chunk-limits.exp-bottle-limit"); - config.addComment(configPath + ".enable", - "Prevent players from crashing the server or other players by\n" + - "creating a ton of THROWN_EXP_BOTTLE entities, then loading\n" + - "them at once.\n" + - "Does not limit the EXP_ORBS, just the bottle entities."); - this.logIsEnabled = config.getBoolean(configPath + ".log", false); - this.maxExpBottlePerChunk = config.getInt(configPath + ".max-exp-bottle-per-chunk", 25, - "Max in a chunk, doesn't limit the actual xp orbs."); - this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 800, - "20 ticks = 1 second"); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onExpBottle(ExpBottleEvent event) { - int expBottleCount = 0; - - for (Entity entity : event.getEntity().getChunk().getEntities()) { - if (entity.getType() != XEntityType.EXPERIENCE_BOTTLE.get()) continue; - - expBottleCount++; - - if (expBottleCount > maxExpBottlePerChunk) { - entity.remove(); - if (logIsEnabled) info("Removed XP-Bottle at " + LocationUtil.toString(entity.getLocation()) + - " because reached limit of " + maxExpBottlePerChunk); - } - } - } - - @Override - public void run() { - for (World world : plugin.getServer().getWorlds()) { - for (Chunk chunk : world.getLoadedChunks()) { - if (!chunk.isLoaded()) continue; - int droppedItemCount = 0; - - for (Entity entity : chunk.getEntities()) { - if (entity.getType() != XEntityType.EXPERIENCE_BOTTLE.get()) continue; - droppedItemCount++; - if (droppedItemCount <= maxExpBottlePerChunk) continue; - - entity.remove(); - if (logIsEnabled) info("Removed XP-Bottle at " + LocationUtil.toString(entity.getLocation()) + - " because reached limit of " + maxExpBottlePerChunk); - } - } - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/FallingBlockLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/FallingBlockLimit.java index 3545e6e1c..425572937 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/FallingBlockLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/FallingBlockLimit.java @@ -2,6 +2,7 @@ import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.models.ChunkUID; import me.xginko.aef.utils.models.ExpiringSet; @@ -15,16 +16,17 @@ import org.bukkit.event.entity.EntityChangeBlockEvent; import java.time.Duration; -import java.util.Set; public class FallingBlockLimit extends AEFModule implements Listener { - private final Set checkedChunks; + private final long chunkCheckDelay; private final int maxFallingGravityBlockPerChunk; private final boolean logIsEnabled; + private ExpiringSet checkedChunks; + public FallingBlockLimit() { - super("chunk-limits.falling-block-limit"); + super("chunk-limits.falling-block-limit", true); config.addComment(configPath + ".enable", "Prevent players from placing massive sand chunks, then collapsing\n" + "them to kill the server."); @@ -32,32 +34,33 @@ public FallingBlockLimit() { this.maxFallingGravityBlockPerChunk = config.getInt(configPath + ".max-falling-gravity-blocks-per-chunk", 60, "Removes any falling block if there is more than x blocks actively\n" + "falling in a chunk."); - this.checkedChunks = new ExpiringSet<>(Duration.ofMillis( - Math.max(1, config.getInt(configPath + ".chunk-check-delay-in-ticks", 20, - "Delay in ticks until the same chunk can be checked again.\n" + - "Prevents overchecking, because physics events can be called many\n" + - "times in a short time for the same chunk.")) * 50L - )); + this.chunkCheckDelay = Math.max(1, config.getInt(configPath + ".chunk-check-delay-in-ticks", 20, + "Delay in ticks until the same chunk can be checked again.\n" + + "Prevents overchecking, because physics events can be called many\n" + + "times in a short time for the same chunk.")) * 50L; } @Override public void enable() { + checkedChunks = new ExpiringSet<>(Duration.ofMillis(chunkCheckDelay)); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (checkedChunks != null) { + checkedChunks.clear(); + checkedChunks.cleanUp(); + checkedChunks = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPhysics(BlockPhysicsEvent event) { Chunk chunk = event.getBlock().getChunk(); + if (ChunkUtil.isRetrievalUnsafe(chunk)) return; + final ChunkUID chunkUID = ChunkUID.of(chunk); if (checkedChunks.contains(chunkUID)) return; @@ -83,8 +86,10 @@ private void onBlockPhysics(BlockPhysicsEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChangeBlock(EntityChangeBlockEvent event) { - if (!event.getEntityType().equals(XEntityType.FALLING_BLOCK.get())) return; + if (event.getEntityType() != XEntityType.FALLING_BLOCK.get()) return; Chunk chunk = event.getBlock().getChunk(); + if (ChunkUtil.isRetrievalUnsafe(chunk)) return; + final ChunkUID chunkUID = ChunkUID.of(chunk); if (checkedChunks.contains(chunkUID)) return; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/MinecartLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/MinecartLimit.java index c6459c292..9a43db254 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/MinecartLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/MinecartLimit.java @@ -1,6 +1,7 @@ package me.xginko.aef.modules.chunklimits; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; @@ -19,11 +20,11 @@ public class MinecartLimit extends AEFModule implements Listener, Runnable { private final long checkPeriod; private final int maxMinecartsPerChunk; private final boolean logIsEnabled; + private BukkitTask bukkitTask; public MinecartLimit() { - super("chunk-limits.minecart-limit"); - config.addComment(configPath + ".enable", + super("chunk-limits.minecart-limit", false, "Limit the amount of minecarts to prevent lag caused by collisions."); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", false); this.maxMinecartsPerChunk = config.getInt(configPath + ".max-minecarts-per-chunk", 25); @@ -37,15 +38,13 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -70,6 +69,7 @@ private void onCreate(VehicleCreateEvent event) { public void run() { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; if (!chunk.isLoaded()) continue; int minecartCount = 0; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/NonLivingEntityLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/NonLivingEntityLimit.java index 0088beb1d..428f08e12 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/NonLivingEntityLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/NonLivingEntityLimit.java @@ -1,6 +1,8 @@ package me.xginko.aef.modules.chunklimits; +import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; @@ -19,11 +21,11 @@ public class NonLivingEntityLimit extends AEFModule implements Listener, Runnabl private final long checkPeriod; private final int maxNonLivingEntities; private final boolean logIsEnabled; + private BukkitTask bukkitTask; public NonLivingEntityLimit() { - super("chunk-limits.entity-limits.non-living-limit"); - config.addComment(configPath + ".enable", + super("chunk-limits.entity-limits.non-living-limit", false, "Limit the amount of non living entities in a chunk to prevent lag.\n" + "Ignores dropped items."); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", true); @@ -38,20 +40,18 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onSpawn(EntitySpawnEvent event) { - if (event.getEntityType().equals(EntityType.DROPPED_ITEM) || EntityUtil.isLivingEntity(event.getEntity())) return; + if (event.getEntityType() == XEntityType.ITEM.get() || EntityUtil.isLivingEntity(event.getEntity())) return; int nonLivingCount = 0; @@ -73,12 +73,13 @@ private void onSpawn(EntitySpawnEvent event) { public void run() { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; if (!chunk.isLoaded()) continue; int nonLivingCount = 0; for (Entity entity : chunk.getEntities()) { - if (entity.getType().equals(EntityType.DROPPED_ITEM)) continue; + if (entity.getType() == XEntityType.ITEM.get()) continue; if (EntityUtil.isLivingEntity(entity)) continue; nonLivingCount++; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/ProjectileLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/ProjectileLimit.java new file mode 100755 index 000000000..73812efd2 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/ProjectileLimit.java @@ -0,0 +1,134 @@ +package me.xginko.aef.modules.chunklimits; + +import com.cryptomorin.xseries.XEntityType; +import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; +import me.xginko.aef.utils.EntityUtil; +import me.xginko.aef.utils.LocationUtil; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.scheduler.BukkitTask; + +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ProjectileLimit extends AEFModule implements Runnable, Listener { + + private final Set exemptEntities; + private final long checkPeriod; + private final int maxProjectilesPerChunk; + private final boolean logIsEnabled; + + private BukkitTask bukkitTask; + + public ProjectileLimit() { + super("chunk-limits.projectile-limit", true, + "Prevent players from crashing the server or other players by\n" + + "creating a ton of projectile entities, then loading them at once."); + this.logIsEnabled = config.getBoolean(configPath + ".log", false); + this.maxProjectilesPerChunk = config.getInt(configPath + ".max-projectiles-per-chunk", 25); + this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 800, + "20 ticks = 1 second"); + final List defaults = Stream.of( + XEntityType.ENDER_PEARL, + XEntityType.FISHING_BOBBER) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList()); + this.exemptEntities = config.getList(configPath + ".whitelisted-types", defaults) + .stream() + .map(configuredEntity -> { + try { + return EntityType.valueOf(configuredEntity); + } catch (IllegalArgumentException e) { + notRecognized(EntityType.class, configuredEntity); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityType.class))); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onProjectileLaunch(ProjectileLaunchEvent event) { + int projectilesCount = 0; + + for (Entity entity : event.getEntity().getChunk().getEntities()) { + if (exemptEntities.contains(entity.getType()) || !EntityUtil.isProjectile(entity)) continue; + + projectilesCount++; + + if (projectilesCount > maxProjectilesPerChunk) { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onProjectileHit(ProjectileHitEvent event) { + int projectilesCount = 0; + + for (Entity entity : event.getEntity().getChunk().getEntities()) { + if (exemptEntities.contains(entity.getType()) || !EntityUtil.isProjectile(entity)) continue; + + projectilesCount++; + + if (projectilesCount > maxProjectilesPerChunk) { + entity.remove(); + if (logIsEnabled) info("Removed Projectile at " + LocationUtil.toString(entity.getLocation()) + + " because reached limit of " + maxProjectilesPerChunk); + } + } + } + + @Override + public void run() { + for (World world : plugin.getServer().getWorlds()) { + for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + if (!chunk.isLoaded()) continue; + + int droppedItemCount = 0; + + for (Entity entity : chunk.getEntities()) { + if (exemptEntities.contains(entity.getType()) || !EntityUtil.isProjectile(entity)) continue; + droppedItemCount++; + if (droppedItemCount <= maxProjectilesPerChunk) continue; + + entity.remove(); + if (logIsEnabled) info("Removed Projectile at " + LocationUtil.toString(entity.getLocation()) + + " because reached limit of " + maxProjectilesPerChunk); + } + } + } + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/TileEntityLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/TileEntityLimit.java index f6eee68cd..3127577e7 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/TileEntityLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/TileEntityLimit.java @@ -1,9 +1,10 @@ package me.xginko.aef.modules.chunklimits; +import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.event.HandlerList; @@ -15,10 +16,11 @@ public class TileEntityLimit extends AEFModule implements Runnable, Listener { private final long checkPeriod; private final int maxTileEntities; private final boolean logIsEnabled; + private BukkitTask bukkitTask; public TileEntityLimit() { - super("chunk-limits.entity-limits.tile-entity-limit"); + super("chunk-limits.entity-limits.tile-entity-limit", false); config.addComment(configPath + ".enable", "Limit the amount of tile entities in a chunk to prevent lag."); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", true); @@ -32,30 +34,32 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @Override public void run() { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + BlockState[] tileEntities = chunk.getTileEntities(); int amountToRemove = tileEntities.length - maxTileEntities; if (amountToRemove <= 0) return; for (int i = 0; i < amountToRemove; i++) { - tileEntities[i].setType(Material.AIR); + tileEntities[i].setType(XMaterial.AIR.get()); + tileEntities[i].update(true, false); + if (logIsEnabled) - info( "Removed tile entity at "+ LocationUtil.toString(tileEntities[i].getLocation())+ - " because reached limit of "+maxTileEntities); + info("Removed tile entity at " + LocationUtil.toString(tileEntities[i].getLocation()) + + " because reached limit of " + maxTileEntities); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/VehicleLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/VehicleLimit.java index 28322a5e9..79ca7223c 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/VehicleLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/VehicleLimit.java @@ -1,6 +1,7 @@ package me.xginko.aef.modules.chunklimits; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; @@ -18,11 +19,11 @@ public class VehicleLimit extends AEFModule implements Listener, Runnable { private final long checkPeriod; private final int maxVehiclesPerChunk; private final boolean logIsEnabled; + private BukkitTask bukkitTask; public VehicleLimit() { - super("chunk-limits.vehicle-limit"); - config.addComment(configPath + ".enable", + super("chunk-limits.vehicle-limit", false, "Limit the amount of vehicles to prevent some lag machines.\n" + "ex. dispenser that spawns a lot of boats into a single location\n" + "then hitting it, causing all boats to explode in every direction."); @@ -38,15 +39,13 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -68,6 +67,7 @@ private void onCreate(VehicleCreateEvent event) { public void run() { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; if (!chunk.isLoaded()) continue; int vehicleCount = 0; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java index f7c3018e4..b95770d0f 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java @@ -2,6 +2,7 @@ import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; import org.bukkit.World; @@ -30,11 +31,12 @@ public class VillagerLimit extends AEFModule implements Runnable, Listener { private final long checkPeriod; private final int maxVillagersPerChunk; private final boolean logIsEnabled, whitelistEnabled; + private BukkitTask bukkitTask; public VillagerLimit() { - super("chunk-limits.entity-limits.villager-limit"); - this.maxVillagersPerChunk = Math.max(config.getInt(configPath + ".max-villagers-per-chunk", 25), 1); + super("chunk-limits.entity-limits.villager-limit", false); + this.maxVillagersPerChunk = Math.max(1, config.getInt(configPath + ".max-villagers-per-chunk", 25)); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", false); this.checkPeriod = Math.max(1, config.getInt(configPath + ".check-period-in-ticks", 600, "check all chunks every x ticks.")); @@ -95,20 +97,18 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onCreatureSpawn(CreatureSpawnEvent event) { - if (event.getEntityType().equals(XEntityType.VILLAGER.get())) { + if (event.getEntityType() == XEntityType.VILLAGER.get()) { this.checkVillagersInChunk(event.getEntity().getChunk()); } } @@ -117,6 +117,8 @@ private void onCreatureSpawn(CreatureSpawnEvent event) { public void run() { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; + if (chunk.isLoaded()) { this.checkVillagersInChunk(chunk); } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/AnchorAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/AnchorAuraDelay.java deleted file mode 100644 index 0142d762d..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/AnchorAuraDelay.java +++ /dev/null @@ -1,101 +0,0 @@ -package me.xginko.aef.modules.combat; - -import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.WorldUtil; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -public class AnchorAuraDelay extends AEFModule implements Listener { - - private final Map placeCooldowns, breakCooldowns; - private final long placeDelayNanos, breakDelayNanos; - private final boolean updateInventory; - - public AnchorAuraDelay() { - super("combat.anchor-aura-delay"); - this.breakCooldowns = new ConcurrentHashMap<>(); - this.breakDelayNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(configPath + ".break-delay-millis", 0, "1 tick = 50 ms")); - this.placeCooldowns = new ConcurrentHashMap<>(); - this.placeDelayNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(configPath + ".place-delay-millis", 400, "1 tick = 50 ms")); - this.updateInventory = config.getBoolean(configPath + ".update-inventory-on-cancel", false, - "Can help with desync but recommended to leave off unless you have issues."); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPlayerInteract(PlayerInteractEvent event) { - if (breakDelayNanos <= 0) return; - if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; - if (event.getClickedBlock().getType() != XMaterial.RESPAWN_ANCHOR.parseMaterial()) return; - if (event.getItem() == null || event.getItem().getType() != XMaterial.GLOWSTONE.parseMaterial()) return; - if (WorldUtil.isRespawnAnchorWorks(event.getPlayer().getWorld())) return; - - if ( - breakCooldowns.containsKey(event.getPlayer().getUniqueId()) - && breakCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { - event.setCancelled(true); - if (updateInventory) event.getPlayer().updateInventory(); - } else { - breakCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + breakDelayNanos); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockPlace(BlockPlaceEvent event) { - if (placeDelayNanos <= 0) return; - if (event.getBlock().getType() != XMaterial.RESPAWN_ANCHOR.parseMaterial()) return; - if (WorldUtil.isRespawnAnchorWorks(event.getPlayer().getWorld())) return; - - if ( - placeCooldowns.containsKey(event.getPlayer().getUniqueId()) - && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { - event.setCancelled(true); - if (updateInventory) event.getPlayer().updateInventory(); - } else { - placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerQuit(PlayerQuitEvent event) { - placeCooldowns.remove(event.getPlayer().getUniqueId()); - breakCooldowns.remove(event.getPlayer().getUniqueId()); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerKick(PlayerKickEvent event) { - placeCooldowns.remove(event.getPlayer().getUniqueId()); - breakCooldowns.remove(event.getPlayer().getUniqueId()); - } -} \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/BedAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/BedAuraDelay.java deleted file mode 100755 index f002632bc..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/BedAuraDelay.java +++ /dev/null @@ -1,100 +0,0 @@ -package me.xginko.aef.modules.combat; - -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.MaterialUtil; -import me.xginko.aef.utils.WorldUtil; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -public class BedAuraDelay extends AEFModule implements Listener { - - private final Map breakCooldowns, placeCooldowns; - private final long breakDelayNanos, placeDelayNanos; - private final boolean updateInventory; - - public BedAuraDelay() { - super("combat.bed-aura-delay"); - this.breakCooldowns = new ConcurrentHashMap<>(); - this.breakDelayNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(configPath + ".break-delay-millis", 0, "1 tick = 50 ms")); - this.placeCooldowns = new ConcurrentHashMap<>(); - this.placeDelayNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(configPath + ".place-delay-millis", 250, "1 tick = 50 ms")); - this.updateInventory = config.getBoolean(configPath + ".update-inventory-on-cancel", false, - "Can help with desync but recommended to leave off unless you have issues."); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPlayerInteract(PlayerInteractEvent event) { - if (breakDelayNanos <= 0) return; - if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; - if (!MaterialUtil.BEDS.contains(event.getClickedBlock().getType())) return; - if (WorldUtil.isBedWorks(event.getClickedBlock().getWorld())) return; - - if ( - breakCooldowns.containsKey(event.getPlayer().getUniqueId()) - && breakCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { - event.setCancelled(true); - if (updateInventory) event.getPlayer().updateInventory(); - } else { - breakCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + breakDelayNanos); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockPlace(BlockPlaceEvent event) { - if (placeDelayNanos <= 0) return; - if (!MaterialUtil.BEDS.contains(event.getBlockPlaced().getType())) return; - if (WorldUtil.isBedWorks(event.getBlockPlaced().getWorld())) return; - - if ( - placeCooldowns.containsKey(event.getPlayer().getUniqueId()) - && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { - event.setCancelled(true); - if (updateInventory) event.getPlayer().updateInventory(); - } else { - placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerQuit(PlayerQuitEvent event) { - placeCooldowns.remove(event.getPlayer().getUniqueId()); - breakCooldowns.remove(event.getPlayer().getUniqueId()); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerKick(PlayerKickEvent event) { - placeCooldowns.remove(event.getPlayer().getUniqueId()); - breakCooldowns.remove(event.getPlayer().getUniqueId()); - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/BowBomb.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/BowBomb.java index eb6c83ef5..e7531a8ba 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/BowBomb.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/BowBomb.java @@ -13,7 +13,7 @@ public class BowBomb extends AEFModule implements Listener { private final int maxBowSquaredVelocity; public BowBomb() { - super("combat.prevent-bow-bomb"); + super("combat.prevent-bow-bomb", false); this.maxBowSquaredVelocity = config.getInt(configPath + ".max-bow-squared-velocity", 15, "Fully pulled bow is ~9-10. 15 is default just to be safe."); } @@ -23,11 +23,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/Burrow.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/Burrow.java index 61fe7c008..5a4df3adc 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/Burrow.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/Burrow.java @@ -33,7 +33,7 @@ public class Burrow extends AEFModule implements Listener { private final boolean shouldTeleportUp, preventIfBlockAboveBurrow, breakAnvilInsteadOfTP, allowSlabs; public Burrow() { - super("combat.prevent-burrow"); + super("combat.prevent-burrow", false); this.damageWhenMovingInBurrow = config.getDouble(configPath + ".damage-when-moving",1.0, "1.0 = Half a heart of damage every time you move."); this.shouldTeleportUp = config.getBoolean(configPath + ".teleport-above-block", true); @@ -49,7 +49,7 @@ public Burrow() { List defaults = Stream.concat(XTag.SHULKER_BOXES.getValues().stream(), Stream.of(XMaterial.AIR, XMaterial.DIRT, XMaterial.DIRT_PATH, XMaterial.SAND, XMaterial.GRAVEL)) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .map(Enum::name) .collect(Collectors.toList()); this.ignoredMaterial = config.getList(configPath + ".ignored-materials", defaults) @@ -71,11 +71,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -104,12 +99,12 @@ private void onPlayerMove(PlayerMoveEvent event) { final Block burrowBlock = playerLocation.getBlock(); if (ignoredMaterial.contains(burrowBlock.getType())) return; - if (!preventIfBlockAboveBurrow && burrowBlock.getRelative(BlockFace.UP).getType() != XMaterial.AIR.parseMaterial()) { + if (!preventIfBlockAboveBurrow && !MaterialUtil.AIR.contains(burrowBlock.getRelative(BlockFace.UP).getType())) { return; } // Beacon and Indestructibles - if (MaterialUtil.SOLID_INDESTRUCTIBLES.contains(burrowBlock.getType()) || burrowBlock.getType() == XMaterial.BEACON.parseMaterial()) { + if (MaterialUtil.SOLID_INDESTRUCTIBLES.contains(burrowBlock.getType()) || burrowBlock.getType() == XMaterial.BEACON.get()) { player.damage(damageWhenMovingInBurrow); if (shouldTeleportUp) teleportUpAndCenter(player, burrowBlock.getLocation()); return; @@ -128,7 +123,7 @@ private void onPlayerMove(PlayerMoveEvent event) { if (MaterialUtil.ANVILS.contains(burrowBlock.getType())) { player.damage(damageWhenMovingInBurrow); if (breakAnvilInsteadOfTP) { - burrowBlock.setType(XMaterial.AIR.parseMaterial()); + burrowBlock.setType(XMaterial.AIR.get()); } else { if (shouldTeleportUp) teleportUpAndCenter(player, burrowBlock.getLocation()); } @@ -136,7 +131,7 @@ private void onPlayerMove(PlayerMoveEvent event) { } // Ender chest & Blocks that are slightly lower in height - if (burrowBlock.getType() == XMaterial.ENDER_CHEST.parseMaterial() || MaterialUtil.SINK_IN_BLOCKS.contains(burrowBlock.getType())) { + if (burrowBlock.getType() == XMaterial.ENDER_CHEST.get() || MaterialUtil.SINK_IN_BLOCKS.contains(burrowBlock.getType())) { if (playerLocation.getY() - playerLocation.getBlockY() < 0.875) { player.damage(damageWhenMovingInBurrow); if (shouldTeleportUp) teleportUpAndCenter(player, burrowBlock.getLocation()); @@ -145,7 +140,7 @@ private void onPlayerMove(PlayerMoveEvent event) { } // Enchantment Table - if (burrowBlock.getType() == XMaterial.ENCHANTING_TABLE.parseMaterial()) { + if (burrowBlock.getType() == XMaterial.ENCHANTING_TABLE.get()) { if (playerLocation.getY() - playerLocation.getBlockY() < 0.75) { player.damage(damageWhenMovingInBurrow); if (shouldTeleportUp) teleportUpAndCenter(player, burrowBlock.getLocation()); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/CrystalAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/CrystalAuraDelay.java deleted file mode 100755 index 20319b10a..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/CrystalAuraDelay.java +++ /dev/null @@ -1,100 +0,0 @@ -package me.xginko.aef.modules.combat; - -import com.cryptomorin.xseries.XEntityType; -import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.modules.AEFModule; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -public class CrystalAuraDelay extends AEFModule implements Listener { - - private final Map breakCooldowns, placeCooldowns; - private final long breakDelayNanos, placeDelayNanos; - private final boolean updateInventory; - - public CrystalAuraDelay() { - super("combat.crystal-aura.regular-delay"); - this.breakCooldowns = new ConcurrentHashMap<>(); - this.breakDelayNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(configPath + ".break-delay-millis", 200, "1 tick = 50 ms")); - this.placeCooldowns = new ConcurrentHashMap<>(); - this.placeDelayNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(configPath + ".place-delay-millis", 0, "1 tick = 50 ms")); - this.updateInventory = config.getBoolean(configPath + ".update-inventory-on-cancel", false, - "Can help with desync but recommended to leave off unless you have issues."); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onEntityDamageByEntity(EntityDamageByEntityEvent event) { - if (breakDelayNanos <= 0) return; - if (event.getEntityType() != XEntityType.END_CRYSTAL.get()) return; - if (event.getDamager().getType() != XEntityType.PLAYER.get()) return; - - if ( - breakCooldowns.containsKey(event.getDamager().getUniqueId()) - && breakCooldowns.get(event.getDamager().getUniqueId()) > System.nanoTime() - ) { - event.setCancelled(true); - if (updateInventory) ((Player) event.getDamager()).updateInventory(); - } else { - breakCooldowns.put(event.getDamager().getUniqueId(), System.nanoTime() + breakDelayNanos); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPlayerInteract(PlayerInteractEvent event) { - if (placeDelayNanos <= 0) return; - if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; // Need to right-click a block to place a crystal - if (event.getItem() == null || event.getItem().getType() != XMaterial.END_CRYSTAL.parseMaterial()) return; - - if ( - placeCooldowns.containsKey(event.getPlayer().getUniqueId()) - && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { - event.setCancelled(true); - if (updateInventory) event.getPlayer().updateInventory(); - } else { - placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerQuit(PlayerQuitEvent event) { - placeCooldowns.remove(event.getPlayer().getUniqueId()); - breakCooldowns.remove(event.getPlayer().getUniqueId()); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerKick(PlayerKickEvent event) { - placeCooldowns.remove(event.getPlayer().getUniqueId()); - breakCooldowns.remove(event.getPlayer().getUniqueId()); - } -} \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/MultiTask.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/MultiTask.java index 3e4fa5562..7ba8e057a 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/MultiTask.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/MultiTask.java @@ -14,7 +14,7 @@ public class MultiTask extends AEFModule implements Listener { public MultiTask() { - super("combat.multi-task-patch"); + super("combat.multi-task-patch", false); } @Override @@ -22,11 +22,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PistonCrystalDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PistonCrystalDelay.java index 20441f57a..6c33bd0ff 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PistonCrystalDelay.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PistonCrystalDelay.java @@ -2,7 +2,6 @@ import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.models.ExpiringSet; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; @@ -11,42 +10,47 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPistonExtendEvent; -import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; public class PistonCrystalDelay extends AEFModule implements Listener { - private final ExpiringSet pistonsPushingCrystals; + private final long cooldownNanos; + + private Map extendCooldowns; public PistonCrystalDelay() { - super("combat.crystal-aura.piston-aura-delay"); - config.addComment(configPath + ".enable", "Rate-limits pistons that extend into crystals"); - this.pistonsPushingCrystals = new ExpiringSet<>(Duration.ofMillis( - Math.max(config.getInt(configPath + ".piston-extend-delay-in-ticks", 40), 1) * 50L)); + super("combat.crystal-aura.piston-aura-delay", false, + "Rate-limits pistons that extend into crystals."); + this.cooldownNanos = TimeUnit.MILLISECONDS.toNanos( + Math.max(1, config.getInt(configPath + ".piston-extend-delay-in-ticks", 40)) * 50L); } @Override public void enable() { + extendCooldowns = new HashMap<>(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (extendCooldowns != null) { + extendCooldowns.clear(); + extendCooldowns = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPistonExtend(BlockPistonExtendEvent event) { for (Entity entity : event.getBlock().getRelative(event.getDirection()).getLocation().getNearbyEntities(1, 1, 1)) { if (entity.getType() == XEntityType.END_CRYSTAL.get()) { - if (pistonsPushingCrystals.contains(event.getBlock().getLocation())) { + if (extendCooldowns.containsKey(event.getBlock().getLocation()) + && extendCooldowns.get(event.getBlock().getLocation()) > System.nanoTime()) { event.setCancelled(true); } else { - pistonsPushingCrystals.add(event.getBlock().getLocation()); + extendCooldowns.put(event.getBlock().getLocation(), System.currentTimeMillis() + cooldownNanos); } return; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PistonPush.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PistonPush.java index b03c60595..b9c6537ac 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PistonPush.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PistonPush.java @@ -20,7 +20,7 @@ public class PistonPush extends AEFModule implements Listener { private final Set pushDisabledTypes; public PistonPush() { - super("combat.piston-push"); + super("combat.piston-push", false); config.addComment(configPath+".enable", "Disables pistons from extending if it would push certain configured entities.\n" + "This can be used to prevent players from pushing other players out of burrows, by\n" + @@ -43,11 +43,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath+".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PortalGodMode.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PortalGodMode.java index 873560cac..06fdab18b 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PortalGodMode.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/PortalGodMode.java @@ -20,39 +20,39 @@ public class PortalGodMode extends AEFModule implements Listener { - private final Cache playersWaitingForPortalTeleport; private final long delayTicks; + private Cache playersWaitingForPortalTeleport; + public PortalGodMode() { - super("combat.portal-god-mode-patch"); - config.addComment(configPath + ".enable", + super("combat.portal-god-mode-patch", false, "Prevents an exploit that allows players to stand in nether portals and not\n" + - "take damage indefinitely by just never sending a TeleportConfirm packet to\n" + - "the server.\n" + - "A similar method is used for the chorus tp exploit, which is not covered\n" + - "by this module."); + "take damage indefinitely by just never sending a TeleportConfirm packet to\n" + + "the server.\n" + + "A similar method is used for the chorus tp exploit, which is not covered\n" + + "by this module."); this.delayTicks = config.getInt(configPath + ".break-portal-delay-ticks", 100, "If the player stays inside the nether portal for this time without teleporting,\n" + "the portal will be broken, making the player inside vulnerable again.\n" + "Nether portal teleports normally happen within ~3s after enter, so 5s (100ticks)\n" + "should be a safe value."); - this.playersWaitingForPortalTeleport = Caffeine.newBuilder() - .expireAfterWrite(Duration.ofMillis((delayTicks * 50L) + 1000L)).build(); // Keep cached content for a second longer just in case } @Override public void enable() { + playersWaitingForPortalTeleport = Caffeine.newBuilder() + .expireAfterWrite(Duration.ofMillis((delayTicks * 50L) + 1000L)).build(); // Keep cached content for a second longer just in case plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (playersWaitingForPortalTeleport != null) { + playersWaitingForPortalTeleport.invalidateAll(); + playersWaitingForPortalTeleport.cleanUp(); + playersWaitingForPortalTeleport = null; + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -63,7 +63,7 @@ private void onEntityPortalEnter(EntityPortalEnterEvent event) { playersWaitingForPortalTeleport.put(event.getEntity().getUniqueId(), plugin.getServer().getScheduler().runTaskLater(plugin, () -> { - event.getLocation().getBlock().setType(XMaterial.AIR.parseMaterial(), true); + event.getLocation().getBlock().setType(XMaterial.AIR.get(), true); playersWaitingForPortalTeleport.invalidate(event.getEntity().getUniqueId()); }, delayTicks)); } @@ -85,7 +85,7 @@ private void onPlayerMove(PlayerMoveEvent event) { @Nullable BukkitTask breakPortalTask = playersWaitingForPortalTeleport.getIfPresent(event.getPlayer().getUniqueId()); if (breakPortalTask == null) return; - if (event.getTo().getBlock().getType() != XMaterial.NETHER_PORTAL.parseMaterial()) { + if (event.getTo().getBlock().getType() != XMaterial.NETHER_PORTAL.get()) { breakPortalTask.cancel(); playersWaitingForPortalTeleport.invalidate(event.getPlayer().getUniqueId()); } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/SilentSwapDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/SilentSwapDelay.java index 4d9c5b1ca..89c87547e 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/SilentSwapDelay.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/SilentSwapDelay.java @@ -2,12 +2,14 @@ import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.inventory.InventoryInteractEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.player.PlayerKickEvent; @@ -20,32 +22,34 @@ public class SilentSwapDelay extends AEFModule implements Listener { - private final Map swapItemCooldowns; private final long cooldownNanos; + private final boolean updateInventory; + + private Map swapItemCooldowns; public SilentSwapDelay() { - super("combat.silent-swap-delay"); - this.swapItemCooldowns = new ConcurrentHashMap<>(); - this.cooldownNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(configPath + ".min-swap-delay-millis", 40L, - "The delay in millis a player cant swap hotbar items after placing\n" + + super("combat.silent-swap-delay", false); + this.updateInventory = config.getBoolean(configPath + ".update-inventory-on-cancel", false, + "Can help with desync but recommended to leave off unless you have issues."); + this.cooldownNanos = TimeUnit.MILLISECONDS.toNanos(config.getLong(configPath + ".min-swap-delay-millis", 40L, + "The delay in millis a player cant swap hotbar items after placing\n" + "a block, clicking a block (for example to place a crystal) or\n" + "damaging an entity. (50 ms = 1 tick)")); } @Override public void enable() { + swapItemCooldowns = new ConcurrentHashMap<>(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (swapItemCooldowns != null) { + swapItemCooldowns.clear(); + swapItemCooldowns = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -54,6 +58,17 @@ private void onPlayerItemHeld(PlayerItemHeldEvent event) { // Fired when a hot b if (swapItemCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime()) { event.setCancelled(true); + if (updateInventory) event.getPlayer().updateInventory(); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onInventoryInteract(InventoryInteractEvent event) { + if (!swapItemCooldowns.containsKey(event.getWhoClicked().getUniqueId())) return; + + if (swapItemCooldowns.get(event.getWhoClicked().getUniqueId()) > System.nanoTime()) { + event.setCancelled(true); + if (updateInventory) ((Player) event.getWhoClicked()).updateInventory(); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java new file mode 100644 index 000000000..a91bee7d8 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java @@ -0,0 +1,52 @@ +package me.xginko.aef.modules.combat.auras; + +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.WorldUtil; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerInteractEvent; + +public class AnchorAuraDelay extends AuraDelayModule { + + public AnchorAuraDelay() { + super("combat.anchor-aura-delay", 0, 400); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPlayerInteract(PlayerInteractEvent event) { + if (breakDelayNanos <= 0) return; + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; + if (event.getClickedBlock().getType() != XMaterial.RESPAWN_ANCHOR.get()) return; + if (event.getItem() == null || event.getItem().getType() != XMaterial.GLOWSTONE.get()) return; + if (WorldUtil.isRespawnAnchorWorks(event.getPlayer().getWorld())) return; + + if ( + breakCooldowns.containsKey(event.getPlayer().getUniqueId()) + && breakCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() + ) { + event.setCancelled(true); + if (updateInventory) event.getPlayer().updateInventory(); + } else { + breakCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + breakDelayNanos); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onBlockPlace(BlockPlaceEvent event) { + if (placeDelayNanos <= 0) return; + if (event.getBlock().getType() != XMaterial.RESPAWN_ANCHOR.get()) return; + if (WorldUtil.isRespawnAnchorWorks(event.getPlayer().getWorld())) return; + + if ( + placeCooldowns.containsKey(event.getPlayer().getUniqueId()) + && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() + ) { + event.setCancelled(true); + if (updateInventory) event.getPlayer().updateInventory(); + } else { + placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); + } + } +} \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java new file mode 100644 index 000000000..4e83c06c2 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java @@ -0,0 +1,81 @@ +package me.xginko.aef.modules.combat.auras; + +import me.xginko.aef.modules.AEFModule; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +public abstract class AuraDelayModule extends AEFModule implements Listener { + + protected final long placeDelayNanos, breakDelayNanos; + protected final boolean updateInventory; + + protected Map placeCooldowns, breakCooldowns; + + public AuraDelayModule(String configPath, long defPlaceDelayMillis, long defBreakDelayMillis) { + this(configPath, false, defPlaceDelayMillis, defBreakDelayMillis); + } + + public AuraDelayModule(String configPath, boolean defEnabled, long defPlaceDelayMillis, long defBreakDelayMillis) { + super(configPath, defEnabled); + this.updateInventory = config.getBoolean(configPath + ".update-inventory-on-cancel", false, + "Can help with desync but recommended to leave off unless you have issues."); + placeDelayNanos = TimeUnit.MILLISECONDS.toNanos( + config.getLong(".place-delay-millis", defPlaceDelayMillis, "1 tick = 50 ms")); + breakDelayNanos = TimeUnit.MILLISECONDS.toNanos( + config.getLong(".break-delay-millis", defBreakDelayMillis)); + } + + @Override + public void enable() { + breakCooldowns = new ConcurrentHashMap<>(); + placeCooldowns = new ConcurrentHashMap<>(); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + if (breakCooldowns != null) { + breakCooldowns.clear(); + breakCooldowns = null; + } + if (placeCooldowns != null) { + placeCooldowns.clear(); + placeCooldowns = null; + } + } + + protected boolean isOnCooldown(UUID uuid, Map cooldownMap, long delayNanos) { + if (delayNanos <= 0) { + return false; + } + + if (cooldownMap.containsKey(uuid) && cooldownMap.get(uuid) > System.nanoTime()) { + return true; + } + + cooldownMap.put(uuid, System.nanoTime() + delayNanos); + return false; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onPlayerQuit(PlayerQuitEvent event) { + placeCooldowns.remove(event.getPlayer().getUniqueId()); + breakCooldowns.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onPlayerKick(PlayerKickEvent event) { + placeCooldowns.remove(event.getPlayer().getUniqueId()); + breakCooldowns.remove(event.getPlayer().getUniqueId()); + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/BedAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/BedAuraDelay.java new file mode 100755 index 000000000..db33d0177 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/BedAuraDelay.java @@ -0,0 +1,51 @@ +package me.xginko.aef.modules.combat.auras; + +import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.WorldUtil; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerInteractEvent; + +public class BedAuraDelay extends AuraDelayModule { + + public BedAuraDelay() { + super("combat.bed-aura-delay", 0, 250); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPlayerInteract(PlayerInteractEvent event) { + if (breakDelayNanos <= 0) return; + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; + if (!MaterialUtil.BEDS.contains(event.getClickedBlock().getType())) return; + if (WorldUtil.isBedWorks(event.getClickedBlock().getWorld())) return; + + if ( + breakCooldowns.containsKey(event.getPlayer().getUniqueId()) + && breakCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() + ) { + event.setCancelled(true); + if (updateInventory) event.getPlayer().updateInventory(); + } else { + breakCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + breakDelayNanos); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onBlockPlace(BlockPlaceEvent event) { + if (placeDelayNanos <= 0) return; + if (!MaterialUtil.BEDS.contains(event.getBlockPlaced().getType())) return; + if (WorldUtil.isBedWorks(event.getBlockPlaced().getWorld())) return; + + if ( + placeCooldowns.containsKey(event.getPlayer().getUniqueId()) + && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() + ) { + event.setCancelled(true); + if (updateInventory) event.getPlayer().updateInventory(); + } else { + placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); + } + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java new file mode 100755 index 000000000..05379e7f5 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java @@ -0,0 +1,51 @@ +package me.xginko.aef.modules.combat.auras; + +import com.cryptomorin.xseries.XEntityType; +import com.cryptomorin.xseries.XMaterial; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; + +public class CrystalAuraDelay extends AuraDelayModule { + + public CrystalAuraDelay() { + super("combat.crystal-aura.regular-delay", 200, 0); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (breakDelayNanos <= 0) return; + if (event.getEntityType() != XEntityType.END_CRYSTAL.get()) return; + if (event.getDamager().getType() != XEntityType.PLAYER.get()) return; + + if ( + breakCooldowns.containsKey(event.getDamager().getUniqueId()) + && breakCooldowns.get(event.getDamager().getUniqueId()) > System.nanoTime() + ) { + event.setCancelled(true); + if (updateInventory) ((Player) event.getDamager()).updateInventory(); + } else { + breakCooldowns.put(event.getDamager().getUniqueId(), System.nanoTime() + breakDelayNanos); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPlayerInteract(PlayerInteractEvent event) { + if (placeDelayNanos <= 0) return; + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; // Need to right-click a block to place a crystal + if (event.getItem() == null || event.getItem().getType() != XMaterial.END_CRYSTAL.get()) return; + + if ( + placeCooldowns.containsKey(event.getPlayer().getUniqueId()) + && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() + ) { + event.setCancelled(true); + if (updateInventory) event.getPlayer().updateInventory(); + } else { + placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); + } + } +} \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/AllayDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/AllayDupe.java new file mode 100755 index 000000000..39a3f2b92 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/AllayDupe.java @@ -0,0 +1,50 @@ +package me.xginko.aef.modules.dupepreventions; + +import com.cryptomorin.xseries.XEntityType; +import me.xginko.aef.modules.AEFModule; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityPickupItemEvent; +import org.bukkit.event.vehicle.VehicleEnterEvent; + +public class AllayDupe extends AEFModule implements Listener { + + private final boolean dismount; + + public AllayDupe() { + super("dupe-preventions.allay-dupe", true, + "Will prevent allays from entering vehicles to prevent a duplication exploit\n" + + "confirmed working in 1.19.4."); + this.dismount = config.getBoolean(configPath + ".dismount-premounted-allays", true); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onVehicleEnter(VehicleEnterEvent event) { + if (event.getEntered().getType() == XEntityType.ALLAY.get()) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntityPickupItem(EntityPickupItemEvent event) { + if (event.getEntityType() != XEntityType.ALLAY.get()) return; + + if (event.getEntity().isInsideVehicle()) { + event.setCancelled(true); + if (dismount) plugin.getServer().getScheduler() + .scheduleSyncDelayedTask(plugin, () -> event.getEntity().leaveVehicle(), 10L); + } + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BookTitleDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BookTitleDupe.java new file mode 100755 index 000000000..329d74855 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BookTitleDupe.java @@ -0,0 +1,77 @@ +package me.xginko.aef.modules.dupepreventions; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.event.PacketListenerPriority; +import com.github.retrooper.packetevents.event.PacketReceiveEvent; +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; +import me.xginko.aef.modules.packets.PacketModule; + +import java.nio.charset.StandardCharsets; + +public class BookTitleDupe extends PacketModule { + + private final int titleLimit, pageLimit, pageCharLimit; + private final boolean log, kick; + + public BookTitleDupe() { + super("dupe-preventions.book-title-dupe", + PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_6) && + PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_21_2), + PacketListenerPriority.HIGHEST, + "Relevant for 1.20.6 - 1.21:\n" + + "Will prevent players from sending book packets with a too large title,\n" + + "to get disconnected and their inventories restored."); + boolean modernLimits = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2); + this.titleLimit = config.getInt(configPath + ".max-title-charlength", modernLimits ? 32 : 128); + this.pageLimit = config.getInt(configPath + ".max-pages", modernLimits ? 100 : 200); + this.pageCharLimit = config.getInt(configPath + ".max-page-charlength", modernLimits ? 1024 : 8192); + this.log = config.getBoolean(configPath + ".log", false); + this.kick = config.getBoolean(configPath + ".kick-player", false); + } + + @Override + public void onPacketReceive(PacketReceiveEvent event) { + if (event.getPacketType() != PacketType.Play.Client.EDIT_BOOK) return; + + if (isIllegalBookEdit(event)) { + event.setCancelled(true); + onCancel(log, kick, event.getUser()); + } + } + + private boolean isIllegalBookEdit(PacketReceiveEvent event) { + int slot = ByteBufHelper.readVarInt(event.getByteBuf()); + + int pageCount = ByteBufHelper.readVarInt(event.getByteBuf()); + if (pageCount > pageLimit) { + return true; + } + + for (int i = 0; i < pageCount; ++i) { + if (isStringTooBig(event.getByteBuf(), pageCharLimit)) { + return true; + } + } + + if (ByteBufHelper.readByte(event.getByteBuf()) != 0) { + return isStringTooBig(event.getByteBuf(), titleLimit); + } + + return false; + } + + private boolean isStringTooBig(Object byteBuf, int charLimit) { + int strBufLen = ByteBufHelper.readVarInt(byteBuf); + + // Check if the received encoded string buffer length is zero or longer than maximum allowed + if (strBufLen < 0 || strBufLen > charLimit * 4) { + return true; + } + + // The received string length is longer than maximum allowed + return ByteBufHelper.toString(byteBuf, ByteBufHelper.readerIndex(byteBuf), strBufLen, StandardCharsets.UTF_8) + .length() > charLimit; + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/ChestedEntitiesInPortals.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/ChestedEntitiesInPortals.java index 018e15f21..3ebe32626 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/ChestedEntitiesInPortals.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/ChestedEntitiesInPortals.java @@ -12,8 +12,7 @@ public class ChestedEntitiesInPortals extends AEFModule implements Listener { public ChestedEntitiesInPortals() { - super("dupe-preventions.prevent-chested-living-entities-in-portals"); - config.addComment(configPath, + super("dupe-preventions.prevent-chested-living-entities-in-portals", false, "Prevents entities that can carry chests from using portals to\n" + "block some common dupe tactics.\n" + "CAUTION: Will remove chests and their contents from a chested\n" + @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -37,9 +31,7 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityPortalEvent(EntityPortalEvent event) { - if (!EntityUtil.isChestableHorse(event.getEntity())) return; - - if (((ChestedHorse) event.getEntity()).isCarryingChest()) { + if (EntityUtil.isChestableHorse(event.getEntity()) && ((ChestedHorse) event.getEntity()).isCarryingChest()) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/ChestsOnEntities.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/ChestsOnEntities.java index af853aa1e..00264c5a7 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/ChestsOnEntities.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/ChestsOnEntities.java @@ -12,8 +12,7 @@ public class ChestsOnEntities extends AEFModule implements Listener { public ChestsOnEntities() { - super("dupe-preventions.prevent-chests-on-living-entities"); - config.addComment(configPath, + super("dupe-preventions.prevent-chests-on-living-entities", false, "Prevent any possible dupes involving chested entities by making\n" + "it impossible to put a chest on them.\n" + "Only do this if you have reason to believe a dupe like that exists\n" + @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoriesOnLogout.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoriesOnLogout.java index bc31b6d8b..58a7b88f5 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoriesOnLogout.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoriesOnLogout.java @@ -14,8 +14,7 @@ public class CloseEntityInventoriesOnLogout extends AEFModule implements Listener { public CloseEntityInventoriesOnLogout() { - super("dupe-preventions.close-entity-inventories-on-player-disconnect"); - config.addComment(configPath, + super("dupe-preventions.close-entity-inventories-on-player-disconnect", false, "Closes open inventories of entities that disappeared when the\n" + "player riding it disconnects."); } @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoryOnChunkUnload.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoryOnChunkUnload.java index 63890060e..beab144a2 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoryOnChunkUnload.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CloseEntityInventoryOnChunkUnload.java @@ -14,8 +14,7 @@ public class CloseEntityInventoryOnChunkUnload extends AEFModule implements Listener { public CloseEntityInventoryOnChunkUnload() { - super("dupe-preventions.close-entity-inventories-on-chunk-unload"); - config.addComment(configPath, + super("dupe-preventions.close-entity-inventories-on-chunk-unload", false, "Closes open inventories of all entities that are in a chunk\n" + "that will be unloaded."); } @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/CowDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CowDupe.java similarity index 75% rename from AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/CowDupe.java rename to AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CowDupe.java index 74257ae56..e07c8b707 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/CowDupe.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CowDupe.java @@ -1,4 +1,4 @@ -package me.xginko.aef.modules.patches; +package me.xginko.aef.modules.dupepreventions; import com.cryptomorin.xseries.XEntityType; import com.cryptomorin.xseries.XMaterial; @@ -10,13 +10,12 @@ import org.bukkit.event.player.PlayerShearEntityEvent; public class CowDupe extends AEFModule implements Listener { + /** * Yoinked from: https://github.com/F3F5/CowDupeFix */ - public CowDupe() { - super("patches.cow-dupe-patch"); - config.addComment(configPath, + super("dupe-preventions.cow-dupe-patch", false, "Patches the cow duplication exploit that allows duping cows using shears.\n" + "Only affects lower versions"); } @@ -26,11 +25,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -40,10 +34,10 @@ public void disable() { private void onPlayerShearEntity(PlayerShearEntityEvent event) { if (event.getEntity().getType() != XEntityType.MOOSHROOM.get()) return; - if (event.getPlayer().hasCooldown(XMaterial.SHEARS.parseMaterial())) { + if (event.getPlayer().hasCooldown(XMaterial.SHEARS.get())) { event.setCancelled(true); } else { - event.getPlayer().setCooldown(XMaterial.SHEARS.parseMaterial(), 2); + event.getPlayer().setCooldown(XMaterial.SHEARS.get(), 2); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/EndPortalDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/EndPortalDupe.java index a2f9763cd..786dab814 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/EndPortalDupe.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/EndPortalDupe.java @@ -4,7 +4,6 @@ import me.xginko.aef.utils.EntityUtil; import org.bukkit.World; import org.bukkit.entity.ChestedHorse; -import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.event.EventHandler; @@ -16,11 +15,10 @@ public class EndPortalDupe extends AEFModule implements Listener { public EndPortalDupe() { - super("dupe-preventions.prevent-end-portal-dupe"); - config.addComment(configPath, + super("dupe-preventions.prevent-end-portal-dupe", false, "Patches a dupe that involves pushing a chestable entity\n" + - "with low hp into an end portal, duplicating its inventory\n" + - "content on death"); + "with low hp into an end portal, duplicating its inventory\n" + + "content on death"); } @Override @@ -28,11 +26,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -40,17 +33,12 @@ public void disable() { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) private void onEntityDamage(EntityDamageEvent event) { - switch (event.getCause()) { - case ENTITY_ATTACK: - case FALL: - return; - } + if (event.getCause() == EntityDamageEvent.DamageCause.ENTITY_ATTACK || event.getCause() == EntityDamageEvent.DamageCause.FALL) return; + if (event.getEntity().getWorld().getEnvironment() != World.Environment.THE_END) return; + if (event.getEntity().getType() == EntityType.PLAYER) return; + if (!EntityUtil.isLivingEntity(event.getEntity())) return; - final Entity entity = event.getEntity(); - if (entity.getType() == EntityType.PLAYER) return; - if (entity.getWorld().getEnvironment() != World.Environment.THE_END) return; - if (!EntityUtil.isLivingEntity(entity)) return; - final LivingEntity livingEntity = (LivingEntity) entity; + final LivingEntity livingEntity = (LivingEntity) event.getEntity(); if ( livingEntity.getCanPickupItems() diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraAtSpawn.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraAtSpawn.java index 3729b0dcc..0366970d2 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraAtSpawn.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraAtSpawn.java @@ -2,11 +2,10 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.config.LanguageCache; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -20,13 +19,11 @@ public class ElytraAtSpawn extends AEFModule implements Listener { private final double spawn_SpeedOldChunks, spawn_SpeedNewChunks, spawn_DenyElytraTPS; - private final boolean spawn_shouldCheckPermission, spawn_DenyElytra, spawn_DenyOnLowTPS, spawn_AlsoRemoveElytraOnLowTPS; + private final boolean spawn_DenyElytra, spawn_DenyOnLowTPS, spawn_AlsoRemoveElytraOnLowTPS; public ElytraAtSpawn() { - super("elytra.elytra-speed.At-Spawn"); - config.addComment(configPath + ".enable", "Use separate values for players at spawn."); - this.spawn_shouldCheckPermission = config.getBoolean(configPath + ".use-bypass-permission", false, - "Can be slow with a lot of players. Enable only if needed."); + super("elytra.elytra-speed.At-Spawn", false, + "Use separate values for players at spawn."); this.spawn_DenyElytra = config.getBoolean(configPath + ".deny-elytra-usage", false); this.spawn_SpeedOldChunks = config.getDouble(configPath + ".speed-old-chunks", 1.0); this.spawn_SpeedNewChunks = config.getDouble(configPath + ".speed-new-chunks", 0.8); @@ -54,7 +51,7 @@ public void disable() { private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); if (!player.isGliding()) return; - if (spawn_shouldCheckPermission && CachingPermTool.hasPermission(AEFPermission.BYPASS_ELYTRA, player)) return; + if (AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_ELYTRA.node()).toBoolean()) return; Location playerLoc = player.getLocation(); if (config.elytra_enable_netherceiling && LocationUtil.isNetherCeiling(playerLoc)) return; if (LocationUtil.getDistance2DTo00(playerLoc) > config.elytra_spawn_radius) return; @@ -72,7 +69,7 @@ private void onPlayerMove(PlayerMoveEvent event) { return; } - if (spawn_DenyOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= spawn_DenyElytraTPS) { + if (spawn_DenyOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= spawn_DenyElytraTPS) { if (config.elytra_teleport_back) player.teleport(ElytraHelper.getInstance().getSetbackLocation(event)); else event.setCancelled(true); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraGlobal.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraGlobal.java index 1b357d97f..2a4a85630 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraGlobal.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraGlobal.java @@ -2,11 +2,10 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.config.LanguageCache; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -21,17 +20,11 @@ public class ElytraGlobal extends AEFModule implements Listener { private final double global_SpeedOldChunks, global_SpeedNewChunks, global_BurstSpeedOldChunks, global_BurstSpeedNewChunks, global_BurstOldChunk_TPS, global_BurstNewChunk_TPS, global_DenyElytraTPS; - private final boolean global_shouldCheckPermission, global_DenyElytra, global_EnableBursting, global_DenyOnLowTPS, - global_AlsoRemoveOnLowTPS; + private final boolean global_DenyElytra, global_EnableBursting, global_DenyOnLowTPS, global_AlsoRemoveOnLowTPS; public ElytraGlobal() { - super("elytra.elytra-speed.Global-Settings"); - config.addComment("elytra.elytra-speed", - "NOTE: Set nocheatplus horizontal elytra settings to 500 or higher."); - config.addComment(configPath + ".enable", + super("elytra.elytra-speed.Global-Settings", false, "Global settings. If nothing else is enabled, this will be used for all environments."); - this.global_shouldCheckPermission = config.getBoolean(configPath + ".use-bypass-permission", false, - "Can be slow with a lot of players. Enable only if needed."); this.global_DenyElytra = config.getBoolean(configPath + ".deny-elytra-usage", false); this.global_SpeedOldChunks = config.getDouble(configPath + ".speed-old-chunks", 1.81); this.global_SpeedNewChunks = config.getDouble(configPath + ".speed-new-chunks", 1.81); @@ -64,7 +57,7 @@ public void disable() { private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); if (!player.isGliding()) return; - if (global_shouldCheckPermission && CachingPermTool.hasPermission(AEFPermission.BYPASS_ELYTRA, player)) return; + if (AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_ELYTRA.node()).toBoolean()) return; Location playerLoc = player.getLocation(); if (config.elytra_enable_netherceiling && LocationUtil.isNetherCeiling(playerLoc)) return; if (config.elytra_enable_at_spawn && LocationUtil.getDistance2DTo00(playerLoc) <= config.elytra_spawn_radius) return; @@ -78,7 +71,7 @@ private void onPlayerMove(PlayerMoveEvent event) { return; } - if (global_DenyOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= global_DenyElytraTPS) { + if (global_DenyOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= global_DenyElytraTPS) { if (config.elytra_teleport_back) player.teleport(ElytraHelper.getInstance().getSetbackLocation(event)); else event.setCancelled(true); @@ -104,7 +97,7 @@ private void onPlayerMove(PlayerMoveEvent event) { if (ElytraHelper.getInstance().isInNewChunks(player)) { // Speed New Chunks - if (global_EnableBursting && AnarchyExploitFixes.getTickReporter().getTPS() >= global_BurstNewChunk_TPS) { + if (global_EnableBursting && AnarchyExploitFixes.tickReporter().getTPS() >= global_BurstNewChunk_TPS) { // Burst Speed New Chunks if (flySpeed > global_BurstSpeedNewChunks) { // Too fast @@ -184,7 +177,7 @@ private void onPlayerMove(PlayerMoveEvent event) { } } else { // Speed Old Chunks - if (global_EnableBursting && AnarchyExploitFixes.getTickReporter().getTPS() >= global_BurstOldChunk_TPS) { + if (global_EnableBursting && AnarchyExploitFixes.tickReporter().getTPS() >= global_BurstOldChunk_TPS) { // Burst Speed Old Chunks if (flySpeed > global_BurstSpeedOldChunks) { if (config.elytra_teleport_back) player.teleport(ElytraHelper.getInstance().getSetbackLocation(event)); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraHelper.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraHelper.java index 18364d30b..bce504dc4 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraHelper.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraHelper.java @@ -36,18 +36,17 @@ public class ElytraHelper extends AEFModule implements Runnable, PacketListener, Listener { private static ElytraHelper instance; - private final Map playerDataMap; - private final PacketListenerAbstract packetListener; + private final long speed_as_ticks = config.elytra_speed_calc_period_millis / 50L; + + private Map playerDataMap; + private PacketListenerAbstract packetListener; private NewChunksListener newChunksListener; private ScheduledExecutorService executorService; private ScheduledFuture scheduledTask; - private final long speed_as_ticks = config.elytra_speed_calc_period_millis / 50L; public ElytraHelper() { super("elytra.elytra-speed"); instance = this; - playerDataMap = new ConcurrentHashMap<>(); - packetListener = asAbstract(PacketListenerPriority.MONITOR); } public static ElytraHelper getInstance() { @@ -56,22 +55,42 @@ public static ElytraHelper getInstance() { @Override public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); + playerDataMap = new ConcurrentHashMap<>(); + packetListener = asAbstract(PacketListenerPriority.MONITOR); PacketEvents.getAPI().getEventManager().registerListener(packetListener); + plugin.getServer().getPluginManager().registerEvents(this, plugin); executorService = Executors.newScheduledThreadPool(1); scheduledTask = executorService.scheduleAtFixedRate( this, 50L, config.elytra_speed_calc_period_millis, TimeUnit.MILLISECONDS); - if (!ChunkUtil.canGetInhabitedTime()) + if (!ChunkUtil.canGetInhabitedTime()) { newChunksListener = new NewChunksListener(); + plugin.getServer().getPluginManager().registerEvents(newChunksListener, plugin); + } } @Override public void disable() { HandlerList.unregisterAll(this); - if (newChunksListener != null) HandlerList.unregisterAll(newChunksListener); - PacketEvents.getAPI().getEventManager().unregisterListener(packetListener); - if (scheduledTask != null) scheduledTask.cancel(true); - if (executorService != null) executorService.shutdown(); + if (newChunksListener != null) { + HandlerList.unregisterAll(newChunksListener); + newChunksListener = null; + } + if (packetListener != null) { + PacketEvents.getAPI().getEventManager().unregisterListener(packetListener); + packetListener = null; + } + if (playerDataMap != null) { + playerDataMap.clear(); + playerDataMap = null; + } + if (scheduledTask != null) { + scheduledTask.cancel(true); + scheduledTask = null; + } + if (executorService != null) { + executorService.shutdownNow(); + executorService = null; + } } @Override diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraOnCeiling.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraOnCeiling.java index e91001dfc..feb5645b6 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraOnCeiling.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraOnCeiling.java @@ -2,11 +2,10 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.config.LanguageCache; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -21,15 +20,12 @@ public class ElytraOnCeiling extends AEFModule implements Listener { private final double ceiling_SpeedOldChunks, ceiling_SpeedNewChunks, ceiling_BurstSpeedOldChunks, ceiling_BurstSpeedNewChunks, ceiling_BurstOldChunk_TPS, ceiling_BurstNewChunk_TPS, ceiling_DenyElytraTPS; - private final boolean ceiling_shouldCheckPermission, ceiling_DenyElytra, ceiling_EnableBursting, ceiling_DenyOnLowTPS, + private final boolean ceiling_DenyElytra, ceiling_EnableBursting, ceiling_DenyOnLowTPS, ceiling_AlsoRemoveOnLowTPS; public ElytraOnCeiling() { - super("elytra.elytra-speed.Nether-Ceiling"); - config.addComment(configPath + ".enable", + super("elytra.elytra-speed.Nether-Ceiling", false, "Use separate values for players above the nether ceiling."); - this.ceiling_shouldCheckPermission = config.getBoolean(configPath + ".use-bypass-permission", false, - "Can be slow with a lot of players. Enable only if needed."); this.ceiling_DenyElytra = config.getBoolean(configPath + ".deny-elytra-usage", false); this.ceiling_SpeedOldChunks = config.getDouble(configPath + ".speed-old-chunks", 0.5); this.ceiling_SpeedNewChunks = config.getDouble(configPath + ".speed-new-chunks", 0.5); @@ -62,7 +58,7 @@ public void disable() { private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); if (!player.isGliding()) return; - if (ceiling_shouldCheckPermission && CachingPermTool.hasPermission(AEFPermission.BYPASS_ELYTRA, player)) return; + if (AnarchyExploitFixes.permissions().permissionValue(player, AEFPermission.BYPASS_ELYTRA.node()).toBoolean()) return; Location playerLoc = player.getLocation(); if (!LocationUtil.isNetherCeiling(playerLoc)) return; @@ -78,7 +74,7 @@ private void onPlayerMove(PlayerMoveEvent event) { return; } - if (ceiling_DenyOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= ceiling_DenyElytraTPS) { + if (ceiling_DenyOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= ceiling_DenyElytraTPS) { if (config.elytra_teleport_back) player.teleport(ElytraHelper.getInstance().getSetbackLocation(event)); else event.setCancelled(true); @@ -105,7 +101,7 @@ private void onPlayerMove(PlayerMoveEvent event) { if (ElytraHelper.getInstance().isInNewChunks(player)) { // Speed New Chunks - if (ceiling_EnableBursting && AnarchyExploitFixes.getTickReporter().getTPS() >= ceiling_BurstNewChunk_TPS) { + if (ceiling_EnableBursting && AnarchyExploitFixes.tickReporter().getTPS() >= ceiling_BurstNewChunk_TPS) { // Burst Speed New Chunks if (flySpeed > ceiling_BurstSpeedNewChunks) { if (config.elytra_teleport_back) player.teleport(ElytraHelper.getInstance().getSetbackLocation(event)); @@ -184,7 +180,7 @@ private void onPlayerMove(PlayerMoveEvent event) { } } else { // Speed Old Chunks - if (ceiling_EnableBursting && AnarchyExploitFixes.getTickReporter().getTPS() >= ceiling_BurstOldChunk_TPS) { + if (ceiling_EnableBursting && AnarchyExploitFixes.tickReporter().getTPS() >= ceiling_BurstOldChunk_TPS) { // Burst Speed Old Chunks if (flySpeed > ceiling_BurstSpeedOldChunks) { if (config.elytra_teleport_back) player.teleport(ElytraHelper.getInstance().getSetbackLocation(event)); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraPacketFly.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraPacketFly.java index fea0553f1..b646943e9 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraPacketFly.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/elytra/ElytraPacketFly.java @@ -20,13 +20,14 @@ public class ElytraPacketFly extends AEFModule implements Listener { - private final Cache elytraOpenCounts; + private final long durationMillis; private final int maxElytraOpensPerTime; private final boolean notify, kickPlayer; + private Cache elytraOpenCounts; + public ElytraPacketFly() { - super("elytra.packet-elytra-fly"); - config.addComment(configPath + ".patch-packet-elytra-fly", + super("elytra.packet-elytra-fly", false, "Patches the future/rusherhack/kamiblue 2b2t elytra fly exploit"); this.maxElytraOpensPerTime = config.getInt(configPath + ".max-glide-toggles-per-time", 25, "The fly exploit causes the player to constantly toggle gliding.\n" + @@ -35,10 +36,8 @@ public ElytraPacketFly() { "Still may trigger false positives when players are jumping and\n" + "sprinting with elytra equipped, so recommended to play around\n" + "with the values."); - this.elytraOpenCounts = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(Math.max(1, - config.getInt(configPath + ".time-in-seconds", 8, - "Time in seconds a elytra open count will be remembered by the plugin.") - ))).build(); + this.durationMillis = Math.max(1, config.getInt(configPath + ".time-in-seconds", 8, + "Time in seconds a elytra open count will be remembered by the plugin.")); this.notify = config.getBoolean(configPath + ".notify-player-to-disable-packetfly", true, "Configure message in lang folder."); this.kickPlayer = config.getBoolean(configPath + ".kick-instead-of-remove-elytra", false, @@ -48,17 +47,17 @@ public ElytraPacketFly() { @Override public void enable() { + elytraOpenCounts = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(durationMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".patch-packet-elytra-fly", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (elytraOpenCounts != null) { + elytraOpenCounts.invalidateAll(); + elytraOpenCounts.cleanUp(); + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/BannedItemNames.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/BannedItemNames.java index 89817925e..d28541b25 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/BannedItemNames.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/BannedItemNames.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.illegals.items; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -24,13 +24,12 @@ public class BannedItemNames extends IllegalItemModule { private final boolean delete; public BannedItemNames() { - super("illegals.banned-item-names", AEFPermission.BYPASS_ILLEGAL_BANNEDNAME); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Resets an item's name (or deletes the item) if it matches one of\n" + - "the configured regexes.\n" + - "Regexes can be complex. Use a tool like https://regex101.com/ or\n" + - "ChatGPT for good results."); + super("illegals.banned-item-names", false, AEFPermission.BYPASS_ILLEGAL_BANNEDNAME, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_BANNEDNAME.node() + "\n" + + "Resets an item's name (or deletes the item) if it matches one of\n" + + "the configured regexes.\n" + + "Regexes can be complex. Use a tool like https://regex101.com/ or\n" + + "ChatGPT for good results."); this.delete = config.getBoolean(configPath + ".delete-item", false, "Will delete the item instead of resetting the name."); this.bannedRegex = config.getList(configPath + ".regex", Collections.singletonList("(?i)illegalstring")) @@ -52,11 +51,6 @@ public BannedItemNames() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if ( @@ -81,7 +75,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality == ItemLegality.ILLEGAL) { if (delete) { diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/BannedMaterials.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/BannedMaterials.java index 838dfd9d0..4535bf74a 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/BannedMaterials.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/BannedMaterials.java @@ -1,9 +1,9 @@ package me.xginko.aef.modules.illegals.items; import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -23,9 +23,8 @@ public class BannedMaterials extends IllegalItemModule { private final boolean checkStored; public BannedMaterials() { - super("illegals.ban-specific-materials", AEFPermission.BYPASS_ILLEGAL_BANNEDMATERIAL); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.ban-specific-materials", false, AEFPermission.BYPASS_ILLEGAL_BANNEDMATERIAL, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_BANNEDMATERIAL.node() + "\n" + "Prevents usage of or deletes items with material that you do not want\n" + "your players to be able to use.\n" + "Useful if your players have blocks that shouldn't be obtainable in survival."); @@ -44,7 +43,7 @@ public BannedMaterials() { XMaterial.NETHER_PORTAL, XMaterial.LIGHT) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .map(Enum::name) .collect(Collectors.toList()); this.bannedMaterials = config.getList(configPath + ".banned-materials", defaults) @@ -61,11 +60,6 @@ public BannedMaterials() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null) { @@ -85,7 +79,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/IllegalItemModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/IllegalItemModule.java index 19549a31f..76ab41f3e 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/IllegalItemModule.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/IllegalItemModule.java @@ -1,19 +1,20 @@ package me.xginko.aef.modules.illegals.items; +import com.cryptomorin.xseries.XMaterial; import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.EntityUtil; import me.xginko.aef.utils.MaterialUtil; import me.xginko.aef.utils.WorldUtil; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.models.ExpiringSet; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Chunk; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.EntityType; @@ -26,15 +27,16 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryInteractEvent; -import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.PlayerAttemptPickupItemEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; @@ -45,6 +47,7 @@ import java.time.Duration; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -52,15 +55,21 @@ public abstract class IllegalItemModule extends AEFModule implements Listener { protected final AEFPermission bypassPermission; - protected final IllegalHandling handling; + protected final IllegalHandling illegalHandling; + protected final boolean guiPluginsSupported; + protected final Set optionalListeners; - private final Cache, ExpiringSet> listenerCooldowns; - private final Function, @PolyNull ExpiringSet> createIfAbsent; + protected final Cache, ExpiringSet> listenerCooldowns; + protected final Function, @PolyNull ExpiringSet> createIfAbsent; public IllegalItemModule(String configPath, AEFPermission bypassPermission) { - super(configPath); + this(configPath, false, bypassPermission, null); + } + + public IllegalItemModule(String configPath, boolean defEnabled, AEFPermission bypassPermission, String comment) { + super(configPath, defEnabled, comment); this.bypassPermission = bypassPermission; - this.optionalListeners = new HashSet<>(); + this.optionalListeners = new HashSet<>(6); String configuredHandling = config.getString(configPath + ".handling", IllegalHandling.PREVENT_USE_ONLY.name(), "Available options:\n" + Arrays.stream(IllegalHandling.values()) @@ -73,15 +82,15 @@ public IllegalItemModule(String configPath, AEFPermission bypassPermission) { handling = IllegalHandling.PREVENT_USE_ONLY; warn("Handling option '" + configuredHandling + "' not recognized. Defaulting to " + handling.name()); } - this.handling = handling; + this.illegalHandling = handling; - final boolean guiPluginsSupported = config.getBoolean(configPath + ".gui-plugins-supported", false, + this.guiPluginsSupported = config.getBoolean(configPath + ".gui-plugins-supported", false, "Enable this if you have problems with the plugin removing items from chest guis."); - if (this.handling == IllegalHandling.STRICT) { + if (this.illegalHandling == IllegalHandling.STRICT) { optionalListeners.add(new Listener() { - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) private void onInventoryOpen(InventoryOpenEvent event) { - if (CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; // Check if the inventory is connected to a location in the game. If it is not, // it was very likely created by a plugin if (!guiPluginsSupported || event.getInventory().getLocation() != null) { @@ -96,13 +105,12 @@ private void onInventoryOpen(InventoryOpenEvent event) { if (config.getBoolean(configPath + ".prevent-hopper32k-mechanic", false, "Prevents Hopper32k mechanic of placing a shulker containing illegals on top\n" + "of a hopper, then using the illegal out of the hopper's inventory.\n" + - "WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource\n" + - "intense as the event fires in high frequencies as soon as players start using\n" + - "farms or item sorters. Recommended to leave off if not necessary.")) { + "No longer hooks into InventoryMoveItemEvent and is therefore way less laggy.")) { optionalListeners.add(new Listener() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onItemGoesThroughHopper(InventoryMoveItemEvent event) { - if (legalityOf(event.getItem()) != ItemLegality.LEGAL) { + private void onPlayerItemHeld(PlayerItemHeldEvent event) { // Fired when a hot bar item selection changes + if (legalityOf(event.getPlayer().getInventory().getItem(event.getNewSlot())) != ItemLegality.LEGAL + || legalityOf(event.getPlayer().getInventory().getItem(event.getPreviousSlot())) != ItemLegality.LEGAL) { event.setCancelled(true); } } @@ -119,11 +127,12 @@ private void onItemGoesThroughHopper(InventoryMoveItemEvent event) { "to handle items separately."); if (checkOnChunkload) { optionalListeners.add(new Listener() { - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) private void onChunkLoad(ChunkLoadEvent event) { if (event.isNewChunk()) return; - Chunk chunk = event.getChunk(); + if (ChunkUtil.isRetrievalUnsafe(chunk)) return; + final int minY = WorldUtil.getMinWorldHeight(event.getWorld()); final int maxY = event.getWorld().getMaxHeight(); @@ -135,7 +144,7 @@ private void onChunkLoad(ChunkLoadEvent event) { if (removeContainers) { if (legalityOf(((InventoryHolder) block.getState(false)).getInventory()) != ItemLegality.LEGAL) - block.setType(Material.AIR, false); + block.setType(XMaterial.AIR.get(), false); } else { BlockState blockState = block.getState(false); for (ItemStack itemStack : ((InventoryHolder) blockState).getInventory()) @@ -172,6 +181,12 @@ public void disable() { HandlerList.unregisterAll(this); optionalListeners.forEach(HandlerList::unregisterAll); optionalListeners.clear(); + for (Map.Entry, ExpiringSet> entry : listenerCooldowns.asMap().entrySet()) { + entry.getValue().clear(); + entry.getValue().cleanUp(); + } + listenerCooldowns.invalidateAll(); + listenerCooldowns.cleanUp(); } public ItemLegality legalityOf(Iterable itemStacks) { @@ -188,21 +203,27 @@ public ItemLegality legalityOf(Iterable itemStacks) { return ItemLegality.LEGAL; } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerItemConsume(PlayerItemConsumeEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + if (legalityOf(event.getItem()) != ItemLegality.LEGAL) { event.setCancelled(true); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onBlockDispense(BlockDispenseEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getBlock().getLocation())) { event.setCancelled(true); return; @@ -214,29 +235,38 @@ public void onBlockDispense(BlockDispenseEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerArmorChange(PlayerArmorChangeEvent event) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // Cant cancel this event + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // Cant cancel this event - if (!CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (!AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) { handleItem(event.getNewItem(), legalityOf(event.getNewItem())); handleItem(event.getOldItem(), legalityOf(event.getOldItem())); } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onInventoryClick(InventoryClickEvent event) { - if (CachingPermTool.hasPermission(bypassPermission, event.getWhoClicked())) return; + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (guiPluginsSupported && event.getInventory().getLocation() == null) return; + if (event.getClick() == ClickType.DROP || event.getClick() == ClickType.CONTROL_DROP + || event.getClick() == ClickType.WINDOW_BORDER_LEFT || event.getClick() == ClickType.WINDOW_BORDER_RIGHT) { + return; + } if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getWhoClicked().getUniqueId())) { event.setCancelled(true); return; } - ItemLegality clickedLegality = legalityOf(event.getCurrentItem()); + if (AnarchyExploitFixes.permissions().permissionValue(event.getWhoClicked(), bypassPermission.node()).toBoolean()) return; + + ItemStack currentItem = event.getCurrentItem(); + ItemLegality clickedLegality = legalityOf(currentItem); if (clickedLegality != ItemLegality.LEGAL) { event.setCancelled(true); - handleItem(event.getCurrentItem(), clickedLegality); + handleItem(currentItem, clickedLegality); + event.setCurrentItem(currentItem); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getWhoClicked().getUniqueId()); } @@ -248,15 +278,18 @@ public void onInventoryClick(InventoryClickEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onInventoryInteract(InventoryInteractEvent event) { - if (CachingPermTool.hasPermission(bypassPermission, event.getWhoClicked())) return; + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) + public void onInventoryDrag(InventoryDragEvent event) { + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (guiPluginsSupported && event.getInventory().getLocation() == null) return; if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getWhoClicked().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getWhoClicked(), bypassPermission.node()).toBoolean()) return; + for (ItemStack invItem : event.getInventory()) { ItemLegality invItemLegality = legalityOf(invItem); if (invItemLegality != ItemLegality.LEGAL) { @@ -267,8 +300,10 @@ public void onInventoryInteract(InventoryInteractEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (event.getDamager().getType() == EntityType.PLAYER) { final Player player = (Player) event.getDamager(); @@ -277,9 +312,11 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { return; } + if (AnarchyExploitFixes.permissions().permissionValue(player, bypassPermission.node()).toBoolean()) return; + ItemStack mainHandItem = player.getInventory().getItemInMainHand(); final ItemLegality mainHandLegality = legalityOf(mainHandItem); - if (mainHandLegality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, player)) { + if (mainHandLegality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(mainHandItem, mainHandLegality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(player.getUniqueId()); @@ -287,7 +324,7 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { ItemStack offHandItem = player.getInventory().getItemInOffHand(); final ItemLegality offHandLegality = legalityOf(offHandItem); - if (offHandLegality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, player)) { + if (offHandLegality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(offHandItem, offHandLegality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(player.getUniqueId()); @@ -298,7 +335,7 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { if (EntityUtil.isLivingEntity(event.getDamager())) { if (legalityOf(((LivingEntity) event.getDamager()).getActiveItem()) != ItemLegality.LEGAL) { event.setCancelled(true); - if (handling != IllegalHandling.PREVENT_USE_ONLY) + if (illegalHandling != IllegalHandling.PREVENT_USE_ONLY) event.getDamager().remove(); return; } @@ -307,22 +344,26 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { if (EntityUtil.isInventoryHolder(event.getDamager())) { if (legalityOf(((InventoryHolder) event.getDamager()).getInventory()) != ItemLegality.LEGAL) { event.setCancelled(true); - if (handling != IllegalHandling.PREVENT_USE_ONLY) + if (illegalHandling != IllegalHandling.PREVENT_USE_ONLY) event.getDamager().remove(); } } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerAttemptPickupItem(PlayerAttemptPickupItemEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack pickUpItem = event.getItem().getItemStack(); final ItemLegality legality = legalityOf(pickUpItem); - if (legality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (legality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(pickUpItem, legality); event.getItem().setItemStack(pickUpItem); @@ -330,16 +371,20 @@ public void onPlayerAttemptPickupItem(PlayerAttemptPickupItemEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerDropItem(PlayerDropItemEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack droppedItem = event.getItemDrop().getItemStack(); final ItemLegality legality = legalityOf(droppedItem); - if (legality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (legality != ItemLegality.LEGAL) { handleItem(droppedItem, legality); event.getItemDrop().setItemStack(droppedItem); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); @@ -348,30 +393,38 @@ public void onPlayerDropItem(PlayerDropItemEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerInteract(PlayerInteractEvent event) { + if (event.useItemInHand() == Event.Result.DENY && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack interactItem = event.getItem(); final ItemLegality legality = legalityOf(interactItem); - if (legality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (legality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(interactItem, legality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + if (event.isCancelled() && illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; + if (listenerCooldowns.get(event.getClass(), createIfAbsent).contains(event.getPlayer().getUniqueId())) { event.setCancelled(true); return; } + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), bypassPermission.node()).toBoolean()) return; + ItemStack handItem = event.getPlayer().getInventory().getItem(event.getHand()); final ItemLegality legality = legalityOf(handItem); - if (legality != ItemLegality.LEGAL && !CachingPermTool.hasPermission(bypassPermission, event.getPlayer())) { + if (legality != ItemLegality.LEGAL) { event.setCancelled(true); handleItem(handItem, legality); listenerCooldowns.get(event.getClass(), createIfAbsent).add(event.getPlayer().getUniqueId()); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/IllegalPotions.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/IllegalPotions.java index 8ebebaad4..4cc3cc990 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/IllegalPotions.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/IllegalPotions.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.illegals.items; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; import org.bukkit.inventory.ItemStack; @@ -15,19 +15,13 @@ public class IllegalPotions extends IllegalItemModule { private final boolean checkStored; public IllegalPotions() { - super("illegals.potions", AEFPermission.BYPASS_ILLEGAL_POTIONS); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Prevents usage of or reverts items with any attribute modifiers\n" + - "or item flags."); + super("illegals.potions", false, AEFPermission.BYPASS_ILLEGAL_POTIONS, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_POTIONS.node() + "\n" + + "Prevents usage of or reverts items with any attribute modifiers\n" + + "or item flags."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || !MaterialUtil.POTIONS.contains(itemStack.getType()) || !itemStack.hasItemMeta()) { @@ -48,7 +42,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class switch (legality) { case CONTAINS_ILLEGAL: diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/InvalidStackSize.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/InvalidStackSize.java index ca5fe7503..df726a735 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/InvalidStackSize.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/InvalidStackSize.java @@ -1,9 +1,10 @@ package me.xginko.aef.modules.illegals.items; import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -24,14 +25,14 @@ public class InvalidStackSize extends IllegalItemModule { public InvalidStackSize() { super("illegals.illegally-stacked-items", AEFPermission.BYPASS_ILLEGAL_OVERSTACKED); config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + "Bypass permission: " + bypassPermission.node() + "\n" + "Prevents usage of or reverts items with a higher or lower\n" + "stack size than their vanilla limit."); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", false); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", true); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", - Collections.singletonList(XMaterial.TOTEM_OF_UNDYING.parseMaterial().name())) + Collections.singletonList(XMaterial.TOTEM_OF_UNDYING.get().name())) .stream() .map(configuredType -> { try { @@ -45,14 +46,9 @@ public InvalidStackSize() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -71,7 +67,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class switch (legality) { case ILLEGAL: diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/PlayerHeads.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/PlayerHeads.java index 1fd8040af..64fca53d6 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/PlayerHeads.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/PlayerHeads.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.illegals.items; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; import org.bukkit.inventory.ItemStack; @@ -14,19 +14,13 @@ public class PlayerHeads extends IllegalItemModule { private final boolean checkStored; public PlayerHeads() { - super("illegals.ban-player-heads", AEFPermission.BYPASS_ILLEGAL_PLAYERHEAD); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.ban-player-heads", false, AEFPermission.BYPASS_ILLEGAL_PLAYERHEAD, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_PLAYERHEAD.node() + "\n" + "Deletes or prevents usage of player heads."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false, "Will delete shulker/bundle if they contain any player heads."); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null) { @@ -46,7 +40,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/SpawnEggs.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/SpawnEggs.java index ed2d6b419..4e5c45bcd 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/SpawnEggs.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/SpawnEggs.java @@ -1,9 +1,9 @@ package me.xginko.aef.modules.illegals.items; import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; import org.bukkit.Material; @@ -23,15 +23,14 @@ public class SpawnEggs extends IllegalItemModule { private final boolean checkStored; public SpawnEggs() { - super("illegals.ban-spawn-eggs", AEFPermission.BYPASS_ILLEGAL_SPAWNEGG); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.ban-spawn-eggs", false, AEFPermission.BYPASS_ILLEGAL_SPAWNEGG, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_SPAWNEGG.node() + "\n" + "Deletes or prevents usage of spawn eggs."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false, "If remove-spawn-eggs is set to true Will delete shulker/bundle\n" + "should they contain any spawneggs."); this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", - Collections.singletonList(XMaterial.VILLAGER_SPAWN_EGG.parseMaterial().name())) + Collections.singletonList(XMaterial.VILLAGER_SPAWN_EGG.get().name())) .stream() .map(configuredType -> { try { @@ -45,11 +44,6 @@ public SpawnEggs() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { if (itemStack == null || whitelistedTypes.contains(itemStack.getType())) { @@ -69,7 +63,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/Unbreakables.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/Unbreakables.java index 787e53276..1ae798d31 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/Unbreakables.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/Unbreakables.java @@ -1,10 +1,11 @@ package me.xginko.aef.modules.illegals.items; import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.utils.ItemUtil; +import me.xginko.aef.utils.MaterialUtil; import me.xginko.aef.utils.PlatformUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -24,14 +25,13 @@ public class Unbreakables extends IllegalItemModule { private final boolean skipZeroDurability, useWhitelist, blacklistMode, checkStored; public Unbreakables() { - super("illegals.revert-unbreakables", AEFPermission.BYPASS_ILLEGAL_UNBREAKABLE); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Deletes and prevents usage of unbreakable items.\n" + - "This can be anything from items with illegal damage attributes to\n" + - "Metadata/NBT tags.\n" + - "Note: Due to the limitations of the API, we can only fully prevent\n" + - "usage of these items by deleting them."); + super("illegals.revert-unbreakables", false, AEFPermission.BYPASS_ILLEGAL_UNBREAKABLE, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_UNBREAKABLE.node() + "\n" + + "Deletes and prevents usage of unbreakable items.\n" + + "This can be anything from items with illegal damage attributes to\n" + + "Metadata/NBT tags.\n" + + "Note: Due to the limitations of the API, we can only fully prevent\n" + + "usage of these items by deleting them."); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", false); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false, @@ -40,7 +40,7 @@ public Unbreakables() { "Make sure to keep enabled on 1.16+, otherwise netherite tools\n" + "will mistakenly be set to max durability, due to some bug in paper."); this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", - Collections.singletonList(XMaterial.DIAMOND_CHESTPLATE.parseMaterial().name())) + Collections.singletonList(XMaterial.DIAMOND_CHESTPLATE.get().name())) .stream() .map(configuredType -> { try { @@ -54,14 +54,9 @@ public Unbreakables() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -88,7 +83,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; switch (legality) { case CONTAINS_ILLEGAL: diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/datavalues/CustomDataValues.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/datavalues/CustomDataValues.java index 66513f506..caca4fd00 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/datavalues/CustomDataValues.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/datavalues/CustomDataValues.java @@ -1,10 +1,11 @@ package me.xginko.aef.modules.illegals.items.datavalues; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; +import me.xginko.aef.utils.MaterialUtil; import me.xginko.aef.utils.PlatformUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -25,12 +26,11 @@ public class CustomDataValues extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public CustomDataValues() { - super("illegals.data-values.custom-data-values", AEFPermission.BYPASS_ILLEGAL_DATA_CUSTOM); - config.addComment(configPath + ".enable", - "1.12 Only. Bypass permission: " + bypassPermission.string() + "\n" + - "Deletes items with configured illegal MaterialData values.\n" + - "Use '/aef datavalue' ingame while holding an item to add the\n" + - "specific value here."); + super("illegals.data-values.custom-data-values", false, AEFPermission.BYPASS_ILLEGAL_DATA_CUSTOM, + "1.12 Only. Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_DATA_CUSTOM.node() + "\n" + + "Deletes items with configured illegal MaterialData values.\n" + + "Use '/aef datavalue' ingame while holding an item to add the\n" + + "specific value here."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.forbiddenDataValues = new HashSet<>(config.getList(configPath + ".data-values", Collections.singletonList("SuperIllegalItem(0)"))); @@ -53,12 +53,12 @@ public CustomDataValues() { @Override public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false) && PlatformUtil.getMinecraftVersion() <= 12; + return configEnabled && PlatformUtil.getMinecraftVersion() <= 12; } @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -77,7 +77,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/datavalues/IllegalGoldenApples.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/datavalues/IllegalGoldenApples.java index 7c163c1ff..968021f44 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/datavalues/IllegalGoldenApples.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/datavalues/IllegalGoldenApples.java @@ -1,9 +1,9 @@ package me.xginko.aef.modules.illegals.items.datavalues; import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.PlatformUtil; @@ -22,27 +22,26 @@ public class IllegalGoldenApples extends IllegalItemModule { private final boolean checkStored; public IllegalGoldenApples() { - super("illegals.data-values.illegal-golden-apples", AEFPermission.BYPASS_ILLEGAL_DATA_APPLE); - config.addComment(configPath + ".enable", - "1.12 Only. Bypass permission: " + bypassPermission.string() + "\n" + - "Deletes apples with illegal MaterialData values. Will use the\n" + - "API to determine what a natural value looks like."); + super("illegals.data-values.illegal-golden-apples", false, AEFPermission.BYPASS_ILLEGAL_DATA_APPLE, + "1.12 Only. Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_DATA_APPLE.node() + "\n" + + "Deletes apples with illegal MaterialData values. Will use the\n" + + "API to determine what a natural value looks like."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); if (XMaterial.GOLDEN_APPLE.isSupported()) { this.allowedAppleData.put( - XMaterial.GOLDEN_APPLE.parseMaterial(), - new MaterialData(XMaterial.GOLDEN_APPLE.parseMaterial())); + XMaterial.GOLDEN_APPLE.get(), + new MaterialData(XMaterial.GOLDEN_APPLE.get())); } if (XMaterial.ENCHANTED_GOLDEN_APPLE.isSupported()) { this.allowedAppleData.put( - XMaterial.ENCHANTED_GOLDEN_APPLE.parseMaterial(), - new MaterialData(XMaterial.ENCHANTED_GOLDEN_APPLE.parseMaterial())); + XMaterial.ENCHANTED_GOLDEN_APPLE.get(), + new MaterialData(XMaterial.ENCHANTED_GOLDEN_APPLE.get())); } } @Override public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false) && PlatformUtil.getMinecraftVersion() <= 12; + return configEnabled && PlatformUtil.getMinecraftVersion() <= 12; } @Override @@ -64,7 +63,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class switch (legality) { case ILLEGAL: diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/HigherEnchants.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/HigherEnchants.java index 572bc019f..944ea41c4 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/HigherEnchants.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/HigherEnchants.java @@ -1,10 +1,13 @@ package me.xginko.aef.modules.illegals.items.enchantments; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XEnchantment; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; +import me.xginko.aef.utils.MaterialUtil; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; @@ -16,6 +19,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -26,25 +30,29 @@ public class HigherEnchants extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored, onlySomeEnchants; public HigherEnchants() { - super("illegals.enchantments.higher-enchants", AEFPermission.BYPASS_ILLEGAL_ENCHANT_HIGHER); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Reverts or prevents usage of ItemStacks with Enchantments higher\n" + - "than the natural, in vanilla survival obtainable level (aka 32ks / 255s)."); + super("illegals.enchantments.higher-enchants", false, AEFPermission.BYPASS_ILLEGAL_ENCHANT_HIGHER, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_ENCHANT_HIGHER.node() + "\n" + + "Reverts or prevents usage of ItemStacks with Enchantments higher\n" + + "than the natural, in vanilla survival obtainable level (aka 32ks / 255s)."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.onlySomeEnchants = config.getBoolean(configPath + ".only-specific-enchants", false); - this.specificEnchants = config.getList(configPath + ".specific-enchants", Collections.singletonList("DIG_SPEED")) + this.specificEnchants = config.getList(configPath + ".specific-enchants", + Collections.singletonList(XEnchantment.EFFICIENCY.get().getName())) .stream() .map(configuredEnchant -> { - final Enchantment enchantment = Enchantment.getByName(configuredEnchant); - if (enchantment == null) notRecognized(Enchantment.class, configuredEnchant); - return enchantment; + Optional enchantment = XEnchantment.of(configuredEnchant); + if (!enchantment.isPresent()) { + notRecognized(Enchantment.class, configuredEnchant); + return null; + } + return enchantment.get().get(); }) .filter(Objects::nonNull) .collect(Collectors.toCollection(HashSet::new)); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", true); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", Collections.singletonList("GOLDEN_APPLE")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + Collections.singletonList(XMaterial.GOLDEN_APPLE.get().name())) .stream() .map(configuredType -> { try { @@ -58,14 +66,9 @@ public HigherEnchants() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -89,7 +92,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { if (legality == ItemLegality.LEGAL) return; - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality == ItemLegality.CONTAINS_ILLEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/InapplicableEnchants.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/InapplicableEnchants.java index 8509d6bde..6855a3bb1 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/InapplicableEnchants.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/InapplicableEnchants.java @@ -1,11 +1,12 @@ package me.xginko.aef.modules.illegals.items.enchantments; -import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; +import me.xginko.aef.utils.MaterialUtil; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; @@ -25,17 +26,16 @@ public class InapplicableEnchants extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public InapplicableEnchants() { - super("illegals.enchantments.inapplicable-enchants", AEFPermission.BYPASS_ILLEGAL_ENCHANT_INAPPLICABLE); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Reverts or prevents usage of ItemStacks with Enchantments that\n" + - "cannot be applied to that ItemStack in vanilla survival minecraft.\n" + - "Examples: A helmet with sharpness or a block of stone with fortune."); + super("illegals.enchantments.inapplicable-enchants", false, AEFPermission.BYPASS_ILLEGAL_ENCHANT_INAPPLICABLE, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_ENCHANT_INAPPLICABLE.node() + "\n" + + "Reverts or prevents usage of ItemStacks with Enchantments that\n" + + "cannot be applied to that ItemStack in vanilla survival minecraft.\n" + + "Examples: A helmet with sharpness or a block of stone with fortune."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", true); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", - Collections.singletonList("GOLDEN_APPLE")) + Collections.singletonList(XMaterial.GOLDEN_APPLE.get().name())) .stream() .map(configuredType -> { try { @@ -49,14 +49,9 @@ public InapplicableEnchants() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return AnarchyExploitFixes.config().getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -78,7 +73,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { if (legality == ItemLegality.LEGAL) return; - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality == ItemLegality.CONTAINS_ILLEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/IncompatibleEnchants.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/IncompatibleEnchants.java index 947aa3501..fb4200f91 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/IncompatibleEnchants.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/enchantments/IncompatibleEnchants.java @@ -1,10 +1,13 @@ package me.xginko.aef.modules.illegals.items.enchantments; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XEnchantment; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; +import me.xginko.aef.utils.MaterialUtil; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; @@ -17,27 +20,6 @@ import java.util.Set; import java.util.stream.Collectors; -import static com.cryptomorin.xseries.XEnchantment.BANE_OF_ARTHROPODS; -import static com.cryptomorin.xseries.XEnchantment.BINDING_CURSE; -import static com.cryptomorin.xseries.XEnchantment.BLAST_PROTECTION; -import static com.cryptomorin.xseries.XEnchantment.CHANNELING; -import static com.cryptomorin.xseries.XEnchantment.DEPTH_STRIDER; -import static com.cryptomorin.xseries.XEnchantment.FIRE_PROTECTION; -import static com.cryptomorin.xseries.XEnchantment.FORTUNE; -import static com.cryptomorin.xseries.XEnchantment.FROST_WALKER; -import static com.cryptomorin.xseries.XEnchantment.INFINITY; -import static com.cryptomorin.xseries.XEnchantment.LOYALTY; -import static com.cryptomorin.xseries.XEnchantment.MENDING; -import static com.cryptomorin.xseries.XEnchantment.MULTISHOT; -import static com.cryptomorin.xseries.XEnchantment.PIERCING; -import static com.cryptomorin.xseries.XEnchantment.PROJECTILE_PROTECTION; -import static com.cryptomorin.xseries.XEnchantment.PROTECTION; -import static com.cryptomorin.xseries.XEnchantment.RIPTIDE; -import static com.cryptomorin.xseries.XEnchantment.SHARPNESS; -import static com.cryptomorin.xseries.XEnchantment.SILK_TOUCH; -import static com.cryptomorin.xseries.XEnchantment.SMITE; -import static com.cryptomorin.xseries.XEnchantment.VANISHING_CURSE; - public class IncompatibleEnchants extends IllegalItemModule { private final Set whitelistedTypes; @@ -45,20 +27,20 @@ public class IncompatibleEnchants extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public IncompatibleEnchants() { - super("illegals.enchantments.incompatible-enchants", AEFPermission.BYPASS_ILLEGAL_ENCHANT_INCOMPATIBLE); - this.damageEnchants = new Enchantment[]{SHARPNESS.getEnchant(), SMITE.getEnchant(), BANE_OF_ARTHROPODS.getEnchant()}; - this.protectionEnchants = new Enchantment[]{PROTECTION.getEnchant(), BLAST_PROTECTION.getEnchant(), - FIRE_PROTECTION.getEnchant(), PROJECTILE_PROTECTION.getEnchant()}; - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Reverts or prevents usage of ItemStacks with Enchantments that\n" + - "cannot coexist in vanilla survival minecraft.\n" + - "Examples: A bow with mending and infinity or armor with every\n" + - "protection enchantment."); + super("illegals.enchantments.incompatible-enchants", false, AEFPermission.BYPASS_ILLEGAL_ENCHANT_INCOMPATIBLE, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_ENCHANT_INCOMPATIBLE.node() + "\n" + + "Reverts or prevents usage of ItemStacks with Enchantments that\n" + + "cannot coexist in vanilla survival minecraft.\n" + + "Examples: A bow with mending and infinity or armor with every\n" + + "protection enchantment."); + this.damageEnchants = new Enchantment[]{XEnchantment.SHARPNESS.get(), XEnchantment.SMITE.get(), XEnchantment.BANE_OF_ARTHROPODS.get()}; + this.protectionEnchants = new Enchantment[]{XEnchantment.PROTECTION.get(), XEnchantment.BLAST_PROTECTION.get(), + XEnchantment.FIRE_PROTECTION.get(), XEnchantment.PROJECTILE_PROTECTION.get()}; this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", true); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", Collections.singletonList("BOW")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + Collections.singletonList(XMaterial.BOW.get().name())) .stream() .map(configuredType -> { try { @@ -72,14 +54,9 @@ public IncompatibleEnchants() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -87,21 +64,21 @@ public boolean shouldEnable() { final Set enchantments = itemStack.getEnchantments().keySet(); if (!enchantments.isEmpty()) { - if (enchantments.contains(SILK_TOUCH.getEnchant()) && enchantments.contains(FORTUNE.getEnchant())) + if (enchantments.contains(XEnchantment.SILK_TOUCH.get()) && enchantments.contains(XEnchantment.FORTUNE.get())) return ItemLegality.ILLEGAL; - if (enchantments.contains(DEPTH_STRIDER.getEnchant()) && enchantments.contains(FROST_WALKER.getEnchant())) + if (enchantments.contains(XEnchantment.DEPTH_STRIDER.get()) && enchantments.contains(XEnchantment.FROST_WALKER.get())) return ItemLegality.ILLEGAL; - if (enchantments.contains(INFINITY.getEnchant()) && enchantments.contains(MENDING.getEnchant())) + if (enchantments.contains(XEnchantment.INFINITY.get()) && enchantments.contains(XEnchantment.MENDING.get())) return ItemLegality.ILLEGAL; - if (enchantments.contains(BINDING_CURSE.getEnchant()) && enchantments.contains(VANISHING_CURSE.getEnchant())) + if (enchantments.contains(XEnchantment.BINDING_CURSE.get()) && enchantments.contains(XEnchantment.VANISHING_CURSE.get())) return ItemLegality.ILLEGAL; - if (RIPTIDE.isSupported()) { - if (enchantments.contains(RIPTIDE.getEnchant()) - && (enchantments.contains(LOYALTY.getEnchant()) || enchantments.contains(CHANNELING.getEnchant()))) + if (XEnchantment.RIPTIDE.isSupported()) { + if (enchantments.contains(XEnchantment.RIPTIDE.get()) + && (enchantments.contains(XEnchantment.LOYALTY.get()) || enchantments.contains(XEnchantment.CHANNELING.get()))) return ItemLegality.ILLEGAL; } - if (MULTISHOT.isSupported()) { - if (enchantments.contains(MULTISHOT.getEnchant()) && enchantments.contains(PIERCING.getEnchant())) + if (XEnchantment.MULTISHOT.isSupported()) { + if (enchantments.contains(XEnchantment.MULTISHOT.get()) && enchantments.contains(XEnchantment.PIERCING.get())) return ItemLegality.ILLEGAL; } @@ -137,7 +114,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { if (legality == ItemLegality.LEGAL) return; - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality == ItemLegality.CONTAINS_ILLEGAL) { itemStack.setAmount(0); @@ -146,48 +123,48 @@ public void handleItem(ItemStack itemStack, ItemLegality legality) { final Set enchantments = itemStack.getEnchantments().keySet(); - if (enchantments.contains(SILK_TOUCH.getEnchant()) && enchantments.contains(FORTUNE.getEnchant())) - itemStack.removeEnchantment(FORTUNE.getEnchant()); - if (enchantments.contains(DEPTH_STRIDER.getEnchant()) && enchantments.contains(FROST_WALKER.getEnchant())) - itemStack.removeEnchantment(FROST_WALKER.getEnchant()); - if (enchantments.contains(INFINITY.getEnchant()) && enchantments.contains(MENDING.getEnchant())) - itemStack.removeEnchantment(INFINITY.getEnchant()); - if (enchantments.contains(BINDING_CURSE.getEnchant()) && enchantments.contains(VANISHING_CURSE.getEnchant())) - itemStack.removeEnchantment(BINDING_CURSE.getEnchant()); - if (RIPTIDE.isSupported()) { // 1.12 doesn't have tridents - if (enchantments.contains(RIPTIDE.getEnchant()) - && (enchantments.contains(LOYALTY.getEnchant()) || enchantments.contains(CHANNELING.getEnchant()))) - itemStack.removeEnchantment(RIPTIDE.getEnchant()); + if (enchantments.contains(XEnchantment.SILK_TOUCH.get()) && enchantments.contains(XEnchantment.FORTUNE.get())) + itemStack.removeEnchantment(XEnchantment.FORTUNE.get()); + if (enchantments.contains(XEnchantment.DEPTH_STRIDER.get()) && enchantments.contains(XEnchantment.FROST_WALKER.get())) + itemStack.removeEnchantment(XEnchantment.FROST_WALKER.get()); + if (enchantments.contains(XEnchantment.INFINITY.get()) && enchantments.contains(XEnchantment.MENDING.get())) + itemStack.removeEnchantment(XEnchantment.INFINITY.get()); + if (enchantments.contains(XEnchantment.BINDING_CURSE.get()) && enchantments.contains(XEnchantment.VANISHING_CURSE.get())) + itemStack.removeEnchantment(XEnchantment.BINDING_CURSE.get()); + if (XEnchantment.RIPTIDE.isSupported()) { // 1.12 doesn't have tridents + if (enchantments.contains(XEnchantment.RIPTIDE.get()) + && (enchantments.contains(XEnchantment.LOYALTY.get()) || enchantments.contains(XEnchantment.CHANNELING.get()))) + itemStack.removeEnchantment(XEnchantment.RIPTIDE.get()); } - if (MULTISHOT.isSupported()) { // 1.12 doesn't have crossbows - if (enchantments.contains(MULTISHOT.getEnchant()) && enchantments.contains(PIERCING.getEnchant())) - itemStack.removeEnchantment(MULTISHOT.getEnchant()); + if (XEnchantment.MULTISHOT.isSupported()) { // 1.12 doesn't have crossbows + if (enchantments.contains(XEnchantment.MULTISHOT.get()) && enchantments.contains(XEnchantment.PIERCING.get())) + itemStack.removeEnchantment(XEnchantment.MULTISHOT.get()); } - if (enchantments.contains(SHARPNESS.getEnchant())) { // Prefer keeping sharpness enchantment if present + if (enchantments.contains(XEnchantment.SHARPNESS.get())) { // Prefer keeping sharpness enchantment if present for (Enchantment dmgEnchant : damageEnchants) { - if (dmgEnchant != SHARPNESS.getEnchant()) { + if (dmgEnchant != XEnchantment.SHARPNESS.get()) { itemStack.removeEnchantment(dmgEnchant); } } - } else if (enchantments.contains(BANE_OF_ARTHROPODS.getEnchant()) && enchantments.contains(SMITE.getEnchant())) { - itemStack.removeEnchantment(BANE_OF_ARTHROPODS.getEnchant()); + } else if (enchantments.contains(XEnchantment.BANE_OF_ARTHROPODS.get()) && enchantments.contains(XEnchantment.SMITE.get())) { + itemStack.removeEnchantment(XEnchantment.BANE_OF_ARTHROPODS.get()); } - if (enchantments.contains(PROTECTION.getEnchant())) { // Prefer keeping protection enchantment if present + if (enchantments.contains(XEnchantment.PROTECTION.get())) { // Prefer keeping protection enchantment if present for (Enchantment protEnchant : protectionEnchants) { - if (protEnchant != PROTECTION.getEnchant()) { + if (protEnchant != XEnchantment.PROTECTION.get()) { itemStack.removeEnchantment(protEnchant); } } - } else if (enchantments.contains(BLAST_PROTECTION.getEnchant())) { // If protection isn't present, prefer blast protection + } else if (enchantments.contains(XEnchantment.BLAST_PROTECTION.get())) { // If protection isn't present, prefer blast protection for (Enchantment protEnchant : protectionEnchants) { - if (protEnchant != BLAST_PROTECTION.getEnchant()) { + if (protEnchant != XEnchantment.BLAST_PROTECTION.get()) { itemStack.removeEnchantment(protEnchant); } } - } else if (enchantments.contains(PROJECTILE_PROTECTION.getEnchant()) && enchantments.contains(FIRE_PROTECTION.getEnchant())) { - itemStack.removeEnchantment(FIRE_PROTECTION.getEnchant()); // If protection and blast protection is not present, prefer projectile protection + } else if (enchantments.contains(XEnchantment.PROJECTILE_PROTECTION.get()) && enchantments.contains(XEnchantment.FIRE_PROTECTION.get())) { + itemStack.removeEnchantment(XEnchantment.FIRE_PROTECTION.get()); // If protection and blast protection is not present, prefer projectile protection } } } \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CommandItems.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CommandItems.java index 11ac2ec1c..7765977e7 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CommandItems.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CommandItems.java @@ -1,11 +1,10 @@ package me.xginko.aef.modules.illegals.items.nbt; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; -import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.checkerframework.checker.nullness.qual.Nullable; import org.jetbrains.annotations.NotNull; @@ -15,23 +14,17 @@ public class CommandItems extends IllegalItemModule { private final boolean checkStored; public CommandItems() { - super("illegals.nbt.command-items", AEFPermission.BYPASS_ILLEGAL_NBT_COMMAND_ITEM); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.nbt.command-items", false, AEFPermission.BYPASS_ILLEGAL_NBT_COMMAND_ITEM, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_NBT_COMMAND_ITEM.node() + "\n" + "Deletes items with commands in their NBT data that run as operator.\n" + "These can only be created by players with creative access.\n" + "Most common items are books, since it allows storing multiple commands."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CustomNBTFilter.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CustomNBTFilter.java index 59dde091c..153748380 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CustomNBTFilter.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/CustomNBTFilter.java @@ -1,10 +1,12 @@ package me.xginko.aef.modules.illegals.items.nbt; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; +import me.xginko.aef.utils.MaterialUtil; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.checkerframework.checker.nullness.qual.Nullable; @@ -24,16 +26,16 @@ public class CustomNBTFilter extends IllegalItemModule { private final boolean useWhitelist, blacklistMode, checkStored; public CustomNBTFilter() { - super("illegals.nbt.ban-custom-tags", AEFPermission.BYPASS_ILLEGAL_NBT_CUSTOM); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + - "Deletes items that have one or more of the configured tags."); + super("illegals.nbt.ban-custom-tags", false, AEFPermission.BYPASS_ILLEGAL_NBT_CUSTOM, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_NBT_CUSTOM.node() + "\n" + + "Deletes items that have one or more of the configured tags."); this.checkStored = config.getBoolean(configPath + ".check-stored-items", false); this.illegalTags = new HashSet<>(config.getList(configPath + ".tags", Collections.singletonList("dmg"), "The exact, case sensitive value of the nbt tag.")); this.useWhitelist = config.getBoolean(configPath + ".item-whitelist-enabled", false); this.blacklistMode = config.getBoolean(configPath + ".use-as-blacklist-instead", false); - this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", Collections.singletonList("GOLDEN_APPLE")) + this.whitelistedTypes = config.getList(configPath + ".whitelisted-items", + Collections.singletonList(XMaterial.GOLDEN_APPLE.get().name())) .stream() .map(configuredType -> { try { @@ -47,14 +49,9 @@ public CustomNBTFilter() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -76,7 +73,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/NBTFilledStorageItem.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/NBTFilledStorageItem.java index bbec50758..16046f4a4 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/NBTFilledStorageItem.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/items/nbt/NBTFilledStorageItem.java @@ -1,9 +1,9 @@ package me.xginko.aef.modules.illegals.items.nbt; import de.tr7zw.changeme.nbtapi.NBT; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.enums.IllegalHandling; -import me.xginko.aef.enums.ItemLegality; +import me.xginko.aef.utils.permissions.AEFPermission; +import me.xginko.aef.utils.enums.IllegalHandling; +import me.xginko.aef.utils.enums.ItemLegality; import me.xginko.aef.modules.illegals.items.IllegalItemModule; import me.xginko.aef.utils.ItemUtil; import me.xginko.aef.utils.MaterialUtil; @@ -24,9 +24,8 @@ public class NBTFilledStorageItem extends IllegalItemModule { private final boolean checkStored; public NBTFilledStorageItem() { - super("illegals.nbt.impossibly-stored-items", AEFPermission.BYPASS_ILLEGAL_NBT_STOREDITEMS); - config.addComment(configPath + ".enable", - "Bypass permission: " + bypassPermission.string() + "\n" + + super("illegals.nbt.impossibly-stored-items", false, AEFPermission.BYPASS_ILLEGAL_NBT_STOREDITEMS, + "Bypass permission: " + AEFPermission.BYPASS_ILLEGAL_NBT_STOREDITEMS.node() + "\n" + "Prevents usage of or deletes storage items that have been pre-filled\n" + "with items using NBT tags. These can only be created by players with\n" + "creative access.\n" + @@ -50,14 +49,9 @@ public NBTFilledStorageItem() { .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public @NotNull ItemLegality legalityOf(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) { + if (itemStack == null || MaterialUtil.AIR.contains(itemStack.getType())) { return ItemLegality.LEGAL; } @@ -74,7 +68,7 @@ public boolean shouldEnable() { @Override public void handleItem(ItemStack itemStack, ItemLegality legality) { - if (handling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class + if (illegalHandling == IllegalHandling.PREVENT_USE_ONLY) return; // We are cancelling the action in the super class if (legality != ItemLegality.LEGAL) { itemStack.setAmount(0); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/PeriodicallyRemoveIllegalBlocks.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/PeriodicallyRemoveIllegalBlocks.java index e466ca115..75648d653 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/PeriodicallyRemoveIllegalBlocks.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/PeriodicallyRemoveIllegalBlocks.java @@ -3,6 +3,7 @@ import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.MaterialUtil; import me.xginko.aef.utils.WorldUtil; import org.bukkit.Chunk; @@ -27,21 +28,25 @@ public class PeriodicallyRemoveIllegalBlocks extends AEFModule implements Runnab private final long checkPeriod; private final double pauseTPS; private final boolean checkShouldPauseOnLowTPS; + private BukkitTask bukkitTask; public PeriodicallyRemoveIllegalBlocks() { - super("illegals.remove-placed-blocks.periodically"); + super("illegals.remove-placed-blocks.periodically", false); List defaults = Stream.of( - XMaterial.CHAIN_COMMAND_BLOCK, + XMaterial.PLAYER_HEAD, + XMaterial.PLAYER_WALL_HEAD, XMaterial.COMMAND_BLOCK, - XMaterial.COMMAND_BLOCK_MINECART, + XMaterial.CHAIN_COMMAND_BLOCK, XMaterial.REPEATING_COMMAND_BLOCK, XMaterial.BEDROCK, - XMaterial.BARRIER) - .map(XMaterial::parseMaterial) - .filter(Objects::nonNull) + XMaterial.BARRIER, + XMaterial.STRUCTURE_BLOCK, + XMaterial.STRUCTURE_VOID, + XMaterial.LIGHT) + .filter(XMaterial::isSupported) + .map(XMaterial::get) .map(Enum::name) - .sorted() .collect(Collectors.toList()); this.blocksToRemove = config.getList(configPath + ".blocks-to-remove", defaults) .stream() @@ -64,22 +69,21 @@ public PeriodicallyRemoveIllegalBlocks() { @Override public void enable() { - bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); + bukkitTask = plugin.getServer().getScheduler() + .runTaskTimer(plugin, this, checkPeriod, checkPeriod); } @Override public void disable() { - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @Override public void run() { - if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; for (World world : plugin.getServer().getWorlds()) { if (exemptedWorlds.contains(world.getName())) continue; @@ -89,6 +93,7 @@ public void run() { final boolean inNether = world.getEnvironment() == World.Environment.NETHER; for (Chunk chunk : world.getLoadedChunks()) { + if (ChunkUtil.isRetrievalUnsafe(chunk)) continue; if (!chunk.isLoaded()) continue; for (int x = 0; x < 16; x++) { @@ -99,28 +104,28 @@ public void run() { // If is skull, check if it is player head if (MaterialUtil.PLAYER_HEADS.contains(block.getType())) { - if (MaterialUtil.isPlayerHead(block.getState())) { - block.setType(XMaterial.AIR.parseMaterial(), false); + if (MaterialUtil.isPlayerHead(block.getState())) { // Necessary additional check due to legacy limitations + block.setType(XMaterial.AIR.get(), false); } continue; } // If is bedrock, make sure not to delete naturally generated - if (block.getType() == XMaterial.BEDROCK.parseMaterial()) { + if (block.getType() == XMaterial.BEDROCK.get()) { if (y > minY + 4) { // offset to not delete natural bedrock floor if (inNether) { // offset to not delete bedrock ceiling if (y < config.nether_ceiling_max_y - 5) - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } else { - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } continue; } // Everything else may be removed - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveIllegalBlocksOnChunkload.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveIllegalBlocksOnChunkload.java index e6329c72c..331245b68 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveIllegalBlocksOnChunkload.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveIllegalBlocksOnChunkload.java @@ -3,9 +3,9 @@ import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.WorldUtil; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.MaterialUtil; -import org.bukkit.Chunk; +import me.xginko.aef.utils.WorldUtil; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -32,19 +32,22 @@ public class RemoveIllegalBlocksOnChunkload extends AEFModule implements Listene private final boolean checkShouldPauseOnLowTPS; public RemoveIllegalBlocksOnChunkload() { - super("illegals.remove-placed-blocks.on-chunkload"); + super("illegals.remove-placed-blocks.on-chunkload", false); config.addComment(configPath + ".enable", "Remove illegally placed blocks on chunkload."); List defaults = Stream.of( - XMaterial.CHAIN_COMMAND_BLOCK, + XMaterial.PLAYER_HEAD, + XMaterial.PLAYER_WALL_HEAD, XMaterial.COMMAND_BLOCK, - XMaterial.COMMAND_BLOCK_MINECART, + XMaterial.CHAIN_COMMAND_BLOCK, XMaterial.REPEATING_COMMAND_BLOCK, XMaterial.BEDROCK, - XMaterial.BARRIER) - .map(XMaterial::parseMaterial) - .filter(Objects::nonNull) + XMaterial.BARRIER, + XMaterial.STRUCTURE_BLOCK, + XMaterial.STRUCTURE_VOID, + XMaterial.LIGHT) + .filter(XMaterial::isSupported) + .map(XMaterial::get) .map(Enum::name) - .sorted() .collect(Collectors.toList()); this.blocksToRemove = config.getList(configPath + ".blocks-to-remove", defaults) .stream() @@ -69,11 +72,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -81,45 +79,44 @@ public void disable() { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { - if (event.isNewChunk() || (checkShouldPauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS)) return; - - Chunk chunk = event.getChunk(); - World world = chunk.getWorld(); - if (exemptedWorlds.contains(world.getName())) return; + if (event.isNewChunk()) return; + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; + if (exemptedWorlds.contains(event.getWorld().getName())) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; - final int minY = WorldUtil.getMinWorldHeight(world); - final int maxY = world.getMaxHeight(); - final boolean inNether = world.getEnvironment() == World.Environment.NETHER; + final int minY = WorldUtil.getMinWorldHeight(event.getWorld()); + final int maxY = event.getWorld().getMaxHeight(); + final boolean inNether = event.getWorld().getEnvironment() == World.Environment.NETHER; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = minY; y < maxY; y++) { - Block block = chunk.getBlock(x, y, z); + Block block = event.getChunk().getBlock(x, y, z); if (!blocksToRemove.contains(block.getType())) continue; // If is skull, check if it is player head if (MaterialUtil.PLAYER_HEADS.contains(block.getType())) { if (MaterialUtil.isPlayerHead(block.getState())) { - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } continue; } // If is bedrock, make sure not to delete naturally generated - if (block.getType() == XMaterial.BEDROCK.parseMaterial()) { + if (block.getType() == XMaterial.BEDROCK.get()) { if (y > minY + 4) { // offset to not delete natural bedrock floor if (inNether) { // offset to not delete bedrock ceiling if (y < config.nether_ceiling_max_y - 5) - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } else { - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } continue; } - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveUnnaturalSpawners.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveUnnaturalSpawners.java index 0beb29a54..46b598dcd 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveUnnaturalSpawners.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/illegals/placedblocks/RemoveUnnaturalSpawners.java @@ -5,9 +5,8 @@ import io.github.thatsmusic99.configurationmaster.api.ConfigSection; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; import me.xginko.aef.utils.WorldUtil; -import org.bukkit.Chunk; -import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.CreatureSpawner; import org.bukkit.entity.EntityType; @@ -17,43 +16,59 @@ import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkLoadEvent; -import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; public class RemoveUnnaturalSpawners extends AEFModule implements Listener { - private final Map> naturalSpawners = new HashMap<>(); + private final Map> naturalSpawners; private final double pauseTPS; private final boolean checkShouldPauseOnLowTPS; public RemoveUnnaturalSpawners() { - super("illegals.remove-unnatural-spawners-on-chunkload"); + super("illegals.remove-unnatural-spawners-on-chunkload", false); this.checkShouldPauseOnLowTPS = config.getBoolean(configPath + ".pause-on-low-TPS", true); this.pauseTPS = config.getDouble(configPath + ".pause-TPS", 14.0); - Map defaults = new HashMap<>(); - defaults.put("world", Arrays.asList( - XEntityType.SKELETON.get().name(), - XEntityType.ZOMBIE.get().name(), - XEntityType.SILVERFISH.get().name(), - XEntityType.SPIDER.get().name(), - XEntityType.CAVE_SPIDER.get().name())); - defaults.put("world_nether", Arrays.asList( - XEntityType.BLAZE.get().name(), - XEntityType.MAGMA_CUBE.get().name())); - defaults.put("world_the_end", Arrays.asList( - XEntityType.SKELETON.get().name(), - XEntityType.SPIDER.get().name())); + Map defaults = new HashMap<>(3); + defaults.put("world", Stream.of( + XEntityType.SKELETON, + XEntityType.ZOMBIE, + XEntityType.SILVERFISH, + XEntityType.SPIDER, + XEntityType.CAVE_SPIDER, + XEntityType.BREEZE) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList())); + defaults.put("world_nether", Stream.of( + XEntityType.BLAZE, + XEntityType.MAGMA_CUBE) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList())); + defaults.put("world_the_end", Stream.of( + XEntityType.SKELETON, + XEntityType.SPIDER) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList())); ConfigSection section = config.getConfigSection(configPath + ".natural-spawner-types-per-world", defaults, "You can add or remove as much world names here as you want."); - for (String configuredWorlds : section.getKeys(false)) { - naturalSpawners.put(configuredWorlds, section.getList(configuredWorlds) + List worlds = section.getKeys(false); + this.naturalSpawners = new HashMap<>(worlds.size()); + for (String world : worlds) { + naturalSpawners.put(world, section.getList(world) .stream() .map(String::valueOf) .map(configuredType -> { @@ -75,11 +90,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -87,23 +97,22 @@ public void disable() { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { - if (event.isNewChunk() || checkShouldPauseOnLowTPS && AnarchyExploitFixes.getTickReporter().getTPS() <= pauseTPS) return; - - Chunk chunk = event.getChunk(); - World world = chunk.getWorld(); - if (!naturalSpawners.containsKey(world.getName())) return; + if (event.isNewChunk()) return; + if (ChunkUtil.isRetrievalUnsafe(event.getChunk())) return; + if (!naturalSpawners.containsKey(event.getWorld().getName())) return; + if (checkShouldPauseOnLowTPS && AnarchyExploitFixes.tickReporter().getTPS() <= pauseTPS) return; - final int minY = WorldUtil.getMinWorldHeight(world); - final int maxY = world.getMaxHeight(); + final int minY = WorldUtil.getMinWorldHeight(event.getWorld()); + final int maxY = event.getWorld().getMaxHeight(); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = minY; y < maxY; y++) { - Block block = chunk.getBlock(x, y, z); - if (block.getType() == XMaterial.SPAWNER.parseMaterial() - && !naturalSpawners.get(world.getName()).contains(((CreatureSpawner) block.getState()).getSpawnedType()) + Block block = event.getChunk().getBlock(x, y, z); + if (block.getType() == XMaterial.SPAWNER.get() + && !naturalSpawners.get(event.getWorld().getName()).contains(((CreatureSpawner) block.getState()).getSpawnedType()) ) { - block.setType(XMaterial.AIR.parseMaterial(), false); + block.setType(XMaterial.AIR.get(), false); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/DisableCustomEntities.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/DisableCustomEntities.java new file mode 100755 index 000000000..bfd073315 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/DisableCustomEntities.java @@ -0,0 +1,71 @@ +package me.xginko.aef.modules.lagpreventions; + +import com.cryptomorin.xseries.XEntityType; +import me.xginko.aef.modules.AEFModule; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntitySpawnEvent; + +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class DisableCustomEntities extends AEFModule implements Listener { + + private final Set disabledEntities; + + public DisableCustomEntities() { + super("lag-preventions.disable-entity-spawns", false, + "Prevent certain entity types from spawning to combat lag.\n" + + "Fish types are enabled by default on newer versions since they\n" + + "can cause a ton of lag."); + + List defaults = Stream.of( + XEntityType.COD, + XEntityType.SALMON, + XEntityType.PUFFERFISH, + XEntityType.TROPICAL_FISH, + XEntityType.BAT, + XEntityType.PHANTOM) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList()); + + this.disabledEntities = config.getList(configPath + ".types", defaults) + .stream() + .map(configuredType -> { + try { + return EntityType.valueOf(configuredType); + } catch (IllegalArgumentException exception) { + notRecognized(EntityType.class, configuredType); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityType.class))); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntitySpawn(EntitySpawnEvent event) { + if (disabledEntities.contains(event.getEntityType())) { + event.setCancelled(true); + } + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/FloodingMachines.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/FloodingMachines.java index e04eacad1..f238bb783 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/FloodingMachines.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/FloodingMachines.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.lagpreventions; +import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.BlockUtil; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -15,8 +15,8 @@ public class FloodingMachines extends AEFModule implements Listener { private final boolean remove; public FloodingMachines() { - super("lag-preventions.prevent-flooding-machines"); - config.addComment(configPath + ".enable", "Will prevent pistons from pushing waterlogged blocks."); + super("lag-preventions.prevent-flooding-machines", false, + "Will prevent pistons from pushing waterlogged blocks."); this.remove = config.getBoolean(configPath + ".delete-waterlogged-blocks", true); } @@ -27,7 +27,7 @@ public void enable() { @Override public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false) && BlockUtil.isWaterloggedAvailable(); + return configEnabled && BlockUtil.isWaterloggedAvailable(); } @Override @@ -39,7 +39,7 @@ public void disable() { private void onPistonExtend(BlockPistonExtendEvent event) { for (Block block : event.getBlocks()) { if (BlockUtil.isWaterlogged(block.getState())) { - if (remove) block.setType(Material.AIR); + if (remove) block.setType(XMaterial.AIR.get()); event.setCancelled(true); return; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/KeepStashLoaded.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/KeepStashLoaded.java index 7d770ac13..4835eba09 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/KeepStashLoaded.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/KeepStashLoaded.java @@ -18,6 +18,7 @@ import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -31,16 +32,16 @@ */ public class KeepStashLoaded extends AEFModule implements Runnable, Listener { - private final Map forceLoadedChunks; - private final Map worldsAndTheirRadiuses = new HashMap<>(); + private final Map worldsAndTheirRadiuses; private final Set storageTypes; - private final long keepLoadedMillis; + private final long keepLoadedMillis, checkDelayTicks; private final int stashCount; private final boolean logIsEnabled, onlyTileEntities; + private Map forceLoadedChunks; + public KeepStashLoaded() { - super("lag-preventions.keep-stash-chunks-loaded"); - this.forceLoadedChunks = new ConcurrentHashMap<>(); + super("lag-preventions.keep-stash-chunks-loaded", false); config.addComment(configPath + ".enable", "Idea by 3b3t admin kumori (Soft1k)\n"+ "Improves lag generated by large stash chunks constantly loading and\n"+ @@ -51,6 +52,9 @@ public KeepStashLoaded() { this.stashCount = config.getInt(configPath + ".container-block-threshold", 50, "How many container blocks have to be in a chunk for it to be seen\n"+ "as a stash chunk to keep force loaded."); + this.checkDelayTicks = config.getInt(configPath + ".check-delay-ticks", 200, + "Ticks to wait after a chunk is loaded before it will be checked.\n" + + "Reduces lag by fast travelling players."); this.keepLoadedMillis = TimeUnit.MINUTES.toMillis(config.getInt(configPath + ".keep-loaded-minutes", 120, "The time in minutes a stash chunks will be kept force loaded before\n"+ "setting it back to normal.")); @@ -80,7 +84,9 @@ public KeepStashLoaded() { ConfigSection section = config.getConfigSection(configPath + ".worlds", defaults, "Radiuses around spawn in chunks (not blocks) that should not be checked.\n" + "Worlds not on this list are exempt from all checking."); - for (String world : section.getKeys(false)) { + List worlds = section.getKeys(false); + this.worldsAndTheirRadiuses = new HashMap<>(worlds.size()); + for (String world : worlds) { try { int radius = Integer.parseInt(section.getString(world)); this.worldsAndTheirRadiuses.put(world, NumberConversions.square(radius)); @@ -92,6 +98,7 @@ public KeepStashLoaded() { @Override public void enable() { + forceLoadedChunks = new ConcurrentHashMap<>(); plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 1L, 20L); } @@ -99,18 +106,22 @@ public void enable() { @Override public void disable() { HandlerList.unregisterAll(this); - for (Map.Entry entry : forceLoadedChunks.entrySet()) { - entry.getKey().getChunkAsync(false).thenAccept(chunk -> { - if (chunk != null) - ChunkUtil.setForceLoaded(chunk, false); - forceLoadedChunks.remove(entry.getKey()); - }); + if (forceLoadedChunks != null) { + for (Map.Entry entry : forceLoadedChunks.entrySet()) { + entry.getKey().getChunkAsync(false).thenAccept(chunk -> { + if (chunk != null) { + ChunkUtil.setForceLoaded(chunk, false); + } + }); + } + forceLoadedChunks.clear(); + forceLoadedChunks = null; } } @Override public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false) && ChunkUtil.canSetChunksForceLoaded(); + return configEnabled && ChunkUtil.canSetChunksForceLoaded(); } @Override @@ -146,29 +157,28 @@ private void onChunkLoad(ChunkLoadEvent event) { if (NumberConversions.square(chunk.getX()) + NumberConversions.square(chunk.getZ()) < worldsAndTheirRadiuses.get(world)) return; - if (isStashChunk(chunk)) { - forceLoadedChunks.computeIfAbsent(ChunkUID.of(chunk), chunkUID -> { - ChunkUtil.setForceLoaded(chunk, true); - if (logIsEnabled) - info("Set chunk " + chunkUID + " to force loaded."); - return System.currentTimeMillis() + keepLoadedMillis; - }); - } - } - - private boolean isStashChunk(Chunk chunk) { - int count = 0; - - if (onlyTileEntities) { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (storageTypes.contains(tileEntity.getType())) { - count++; - if (count > stashCount) { - return true; + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> { + if (!chunk.isLoaded()) return; + + int count = 0; + + if (onlyTileEntities) { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (storageTypes.contains(tileEntity.getType())) { + count++; + if (count > stashCount) { + ChunkUtil.setForceLoaded(chunk, true); + forceLoadedChunks.computeIfAbsent(ChunkUID.of(chunk), chunkUID -> { + if (logIsEnabled) info("Set chunk " + chunkUID + " to force loaded."); + return System.currentTimeMillis() + keepLoadedMillis; + }); + return; + } } } + return; } - } else { + final int minY = WorldUtil.getMinWorldHeight(chunk.getWorld()); final int maxY = chunk.getWorld().getMaxHeight(); @@ -178,14 +188,17 @@ private boolean isStashChunk(Chunk chunk) { if (storageTypes.contains(chunk.getBlock(x, y, z).getType())) { count++; if (count > stashCount) { - return true; + ChunkUtil.setForceLoaded(chunk, true); + forceLoadedChunks.computeIfAbsent(ChunkUID.of(chunk), chunkUID -> { + if (logIsEnabled) info("Set chunk " + chunkUID + " to force loaded."); + return System.currentTimeMillis() + keepLoadedMillis; + }); + return; } } } } } - } - - return false; + }, checkDelayTicks); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/LeverSpam.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/LeverSpam.java index bd987b781..7a83da176 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/LeverSpam.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/LeverSpam.java @@ -4,10 +4,8 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.config.Config; import me.xginko.aef.modules.AEFModule; import org.bukkit.Location; -import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -21,47 +19,50 @@ public class LeverSpam extends AEFModule implements Listener { - private final Cache leverLocationCooldowns; - private final Cache playersUsingLeversCooldowns; + private final long cacheTimeMillis; private final int leverUsageLimit; private final boolean shouldKickPlayer, sendActionBar; + private Cache leverLocationCooldowns; + private Cache playersUsingLeversCooldowns; + public LeverSpam() { - super("lag-preventions.prevent-lever-spam"); - Config config = AnarchyExploitFixes.config(); - config.addComment(configPath + ".enable", "Rate Limit levers to prevent a lag exploit."); + super("lag-preventions.prevent-lever-spam", false, + "Rate Limit levers to prevent a lag exploit."); this.sendActionBar = config.getBoolean(configPath + ".show-actionbar", true); this.shouldKickPlayer = config.getBoolean(configPath + ".kick-player", false); this.leverUsageLimit = config.getInt(configPath + ".max-lever-usages-per-time", 15); - final long cacheTimeMillis = config.getInt(configPath + ".lever-time-in-ticks", 40) * 50L; - this.leverLocationCooldowns = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); - this.playersUsingLeversCooldowns = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); + this.cacheTimeMillis = config.getInt(configPath + ".lever-time-in-ticks", 40) * 50L; } @Override public void enable() { + leverLocationCooldowns = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); + playersUsingLeversCooldowns = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (leverLocationCooldowns != null) { + leverLocationCooldowns.invalidateAll(); + leverLocationCooldowns.cleanUp(); + leverLocationCooldowns = null; + } + if (playersUsingLeversCooldowns != null) { + playersUsingLeversCooldowns.invalidateAll(); + playersUsingLeversCooldowns.cleanUp(); + playersUsingLeversCooldowns = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onInteract(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; - Block clicked = event.getClickedBlock(); - if (clicked.getType() != XMaterial.LEVER.parseMaterial()) return; - - final Player player = event.getPlayer(); + if (event.getClickedBlock().getType() != XMaterial.LEVER.get()) return; - final Location leverLoc = clicked.getLocation(); + final Location leverLoc = event.getClickedBlock().getLocation(); Integer activationCount = leverLocationCooldowns.getIfPresent(leverLoc); if (activationCount == null) activationCount = 0; @@ -71,30 +72,29 @@ private void onInteract(PlayerInteractEvent event) { if (activationCount > leverUsageLimit) { event.setCancelled(true); if (shouldKickPlayer) { - player.kickPlayer(AnarchyExploitFixes.getLang(player.getLocale()).lagpreventions_stopSpammingLevers); + event.getPlayer().kickPlayer(AnarchyExploitFixes.getLang(event.getPlayer().getLocale()).lagpreventions_stopSpammingLevers); return; } if (sendActionBar) { - player.sendActionBar(AnarchyExploitFixes.getLang(player.getLocale()).lagpreventions_stopSpammingLevers); + event.getPlayer().sendActionBar(AnarchyExploitFixes.getLang(event.getPlayer().getLocale()).lagpreventions_stopSpammingLevers); } return; } - final UUID playerUniqueId = player.getUniqueId(); - Integer leverFlickCount = playersUsingLeversCooldowns.getIfPresent(playerUniqueId); + Integer leverFlickCount = playersUsingLeversCooldowns.getIfPresent(event.getPlayer().getUniqueId()); if (leverFlickCount == null) leverFlickCount = 0; leverFlickCount++; - playersUsingLeversCooldowns.put(playerUniqueId, leverFlickCount); + playersUsingLeversCooldowns.put(event.getPlayer().getUniqueId(), leverFlickCount); if (leverFlickCount > leverUsageLimit) { event.setCancelled(true); if (shouldKickPlayer) { - player.kickPlayer(AnarchyExploitFixes.getLang(player.getLocale()).lagpreventions_stopSpammingLevers); + event.getPlayer().kickPlayer(AnarchyExploitFixes.getLang(event.getPlayer().getLocale()).lagpreventions_stopSpammingLevers); return; } if (sendActionBar) { - player.sendActionBar(AnarchyExploitFixes.getLang(player.getLocale()).lagpreventions_stopSpammingLevers); + event.getPlayer().sendActionBar(AnarchyExploitFixes.getLang(event.getPlayer().getLocale()).lagpreventions_stopSpammingLevers); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/NoShulkerDrops.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/NoShulkerDrops.java index 0615eebf7..0a6e02ab7 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/NoShulkerDrops.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/NoShulkerDrops.java @@ -13,8 +13,7 @@ public class NoShulkerDrops extends AEFModule implements Listener { public NoShulkerDrops() { - super("lag-preventions.anti-shulker-drops"); - config.addComment(configPath + ".enable", + super("lag-preventions.anti-shulker-drops", false, "Disables shulkers dropping stored items when blown up.\n" + "This helps fix client- and serverside lag when done often and fast."); } @@ -24,11 +23,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -37,10 +31,13 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityDamage(EntityDamageEvent event) { if (event.getEntityType() != XEntityType.ITEM.get()) return; - Item item = (Item) event.getEntity(); - if (MaterialUtil.SHULKER_BOXES.contains(item.getItemStack().getType())) { - event.setCancelled(true); // Cancel damage so the drop logic doesn't happen - item.remove(); // remove entity + + if (event.getCause() == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION || event.getCause() == EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) { + Item item = (Item) event.getEntity(); + if (MaterialUtil.SHULKER_BOXES.contains(item.getItemStack().getType())) { + event.setCancelled(true); // Cancel damage so the drop logic doesn't happen + item.remove(); // remove entity + } } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/StashExplosions.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/StashExplosions.java index db897e6a1..8e4d14aaa 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/StashExplosions.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/StashExplosions.java @@ -1,5 +1,7 @@ package me.xginko.aef.modules.lagpreventions; +import com.cryptomorin.xseries.XEntityType; +import com.cryptomorin.xseries.XMaterial; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.modules.AEFModule; @@ -24,26 +26,25 @@ public class StashExplosions extends AEFModule implements Listener { - private final Cache containerExplosions; private final Set storageTypes; + private final long waitTimeSeconds; private final int amountAtWhichToTakeAction; private final boolean logIsEnabled; + private Cache containerExplosions; + public StashExplosions() { - super("lag-preventions.disable-item-drops-during-large-stash-explosions"); - config.addComment(configPath + ".enable", + super("lag-preventions.disable-item-drops-during-large-stash-explosions", false, "Explodes containers without dropping items after a certain amount\n" + - "of exploded containers per chunk."); + "of exploded containers per chunk."); this.logIsEnabled = config.getBoolean(configPath + ".log", false); this.amountAtWhichToTakeAction = config.getInt(configPath + ".min-explosions-before-drops-disable", 6, "How many container blocks in a chunk can be blown up until items \n" + - "no longer drop from them."); - this.containerExplosions = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds( - Math.max(1, config.getInt(configPath + ".time-in-seconds", 3, - "The time in seconds to wait after an explosion for another one to happen.\n" + + "no longer drop from them."); + this.waitTimeSeconds = Math.max(1, config.getInt(configPath + ".time-in-seconds", 3, + "The time in seconds to wait after an explosion for another one to happen.\n" + "If no explosion happens within x seconds after the first one, the count\n" + - "resets to 0.")) - )).build(); + "resets to 0.")); this.storageTypes = config.getList(configPath + ".container-types", MaterialUtil.INVENTORY_HOLDERS .stream() .filter(material -> !MaterialUtil.SHULKER_BOXES.contains(material)) @@ -63,18 +64,18 @@ public StashExplosions() { @Override public void enable() { + containerExplosions = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(waitTimeSeconds)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - containerExplosions.cleanUp(); + if (containerExplosions != null) { + containerExplosions.invalidateAll(); + containerExplosions.cleanUp(); + containerExplosions = null; + } } private void handleExplosion(Chunk chunk, List affectedBlocks) { @@ -90,7 +91,7 @@ private void handleExplosion(Chunk chunk, List affectedBlocks) { affectedBlocks.removeIf(block -> { if (storageTypes.contains(block.getType())) { - block.setType(Material.AIR); + block.setType(XMaterial.AIR.get()); return true; } return false; @@ -115,6 +116,9 @@ private void onBlockExplode(BlockExplodeEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityExplode(EntityExplodeEvent event) { + if (event.getEntityType() == XEntityType.WIND_CHARGE.get()) return; + if (event.getEntityType() == XEntityType.BREEZE_WIND_CHARGE.get()) return; + handleExplosion(event.getEntity().getChunk(), event.blockList()); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/CustomAgeLimits.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/CustomAgeLimits.java index ab16fbfe9..53847a416 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/CustomAgeLimits.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/CustomAgeLimits.java @@ -23,11 +23,11 @@ public class CustomAgeLimits extends AEFModule implements Runnable, Listener { private final Map entityLimits = new EnumMap<>(EntityType.class); private final long checkPeriod; private final boolean logIsEnabled; + private BukkitTask bukkitTask; public CustomAgeLimits() { - super("lag-preventions.entity-age-limits.custom-limits"); - config.addComment(configPath + ".enable", + super("lag-preventions.entity-age-limits.custom-limits", false, "Kill certain entities after a custom amount of ticks lived."); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", false); this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 1200, @@ -70,22 +70,20 @@ public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - if (bukkitTask != null) bukkitTask.cancel(); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @Override public void run() { for (World world : plugin.getServer().getWorlds()) { for (Entity entity : world.getEntities()) { - if (entityLimits.containsKey(entity.getType()) && entity.getTicksLived() >= entityLimits.get(entity.getType())) { + if (entityLimits.containsKey(entity.getType()) && entity.getTicksLived() > entityLimits.get(entity.getType())) { entity.remove(); if (logIsEnabled) info("Removed " + entity.getType().name() + " due to old age."); } @@ -98,7 +96,7 @@ private void onChunkLoad(ChunkLoadEvent event) { if (event.isNewChunk()) return; for (Entity entity : event.getChunk().getEntities()) { - if (entityLimits.containsKey(entity.getType()) && entity.getTicksLived() >= entityLimits.get(entity.getType())) { + if (entityLimits.containsKey(entity.getType()) && entity.getTicksLived() > entityLimits.get(entity.getType())) { entity.remove(); if (logIsEnabled) info("Removed " + entity.getType().name() + " due to old age."); } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java index 82c9868f4..065b6fad4 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java @@ -4,17 +4,22 @@ import me.xginko.aef.utils.EntityUtil; import org.bukkit.World; import org.bukkit.entity.Entity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.scheduler.BukkitTask; -public class ProjectileAgeLimit extends AEFModule implements Runnable { +public class ProjectileAgeLimit extends AEFModule implements Runnable, Listener { private final long checkPeriod; private final int max_alive_time; + private BukkitTask bukkitTask; public ProjectileAgeLimit() { - super("lag-preventions.entity-age-limits.projectile-limit"); - config.addComment(configPath + ".enable", + super("lag-preventions.entity-age-limits.projectile-limit", false, "Patches any lag exploit that abuses spawning a ton of projectile entities\n" + "(ex. Snowball exploit)." + "Skips over the following entities: ENDER_PEARL, FISHING_HOOK, WITHER_SKULL\n" + @@ -29,16 +34,16 @@ public ProjectileAgeLimit() { @Override public void enable() { bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); + plugin.getServer().getPluginManager().registerEvents(this, plugin); } @Override public void disable() { - if (bukkitTask != null) bukkitTask.cancel(); + HandlerList.unregisterAll(this); + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } } @Override @@ -61,4 +66,25 @@ public void run() { } } } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onChunkLoad(ChunkLoadEvent event) { + if (event.isNewChunk()) return; + + for (Entity entity : event.getChunk().getEntities()) { + if (EntityUtil.isProjectile(entity)) { + switch (entity.getType()) { + case ENDER_PEARL: + case WITHER_SKULL: + case FISHING_HOOK: + case ENDER_SIGNAL: + continue; + } + + if (entity.getTicksLived() > max_alive_time) { + entity.remove(); + } + } + } + } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockFormOrGrow.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockFormOrGrow.java index 9347d3a20..3561d1c1e 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockFormOrGrow.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockFormOrGrow.java @@ -1,52 +1,53 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.GenericUtil; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockSpreadEvent; -public class BlockFormOrGrow extends RegionalActivityModule { - - private final int limit; +public class BlockFormOrGrow extends RegionalBlockActivityModule { public BlockFormOrGrow() { super( "block-spread", false, + true, + 2000, 1500.0, 6000, 10000, 10.0, - 120.0 - ); - config.addComment(configPath+".enable", + 120.0, + GenericUtil.mapOfEntries( + GenericUtil.mapEntry(XMaterial.ICE, 1000), + GenericUtil.mapEntry(XMaterial.SNOW, 1000)), "Limits blocks spreading or forming based on world conditions within a\n" + - "configurable radius and timeframe to help reduce lag by cancelling burst\n" + - "activity hotspots.\n" + - "\n" + - "Examples:\n" + - "\n" + - "- Snow forming due to a snow storm.\n" + - "- Ice forming in a snowy Biome like Taiga or Tundra.\n" + - "- Obsidian / Cobblestone forming due to contact with water.\n" + - "- Concrete forming due to mixing of concrete powder and water.\n" + - "- Mushrooms spreading.\n" + - "- Fire spreading."); - this.limit = config.getInt(configPath + ".block-form-event-limit", 800, - "Maximum number of times a block can form or spread within the configured\n" + - "timeframe before activity will be put on cooldown."); + "configurable radius and timeframe to help reduce lag by cancelling burst\n" + + "activity hotspots.\n" + + "\n" + + "Examples:\n" + + "\n" + + "- Snow forming due to a snow storm.\n" + + "- Ice forming in a snowy Biome like Taiga or Tundra.\n" + + "- Obsidian / Cobblestone forming due to contact with water.\n" + + "- Concrete forming due to mixing of concrete powder and water.\n" + + "- Mushrooms spreading.\n" + + "- Fire spreading." + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockForm(BlockFormEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockSpread(BlockSpreadEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockPhysics.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockPhysics.java index 2fa898a08..1d8dd4b58 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockPhysics.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/BlockPhysics.java @@ -1,43 +1,44 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.GenericUtil; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPhysicsEvent; -public class BlockPhysics extends RegionalActivityModule { - - private final int limit; +public class BlockPhysics extends RegionalBlockActivityModule { public BlockPhysics() { super( "block-physics", + false, true, + 512000, 1500.0, 18000, 20000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", + 120.0, + GenericUtil.mapOfEntries( + GenericUtil.mapEntry(XMaterial.WATER, 256000), + GenericUtil.mapEntry(XMaterial.LAVA, 256000)), "Limits block physics within a configurable radius and timeframe\n" + - "to help reduce lag by cancelling burst activity hotspots.\n" + - "\n" + - "Note:\n" + - "\n" + - "The event used for this check (BlockPhysicsEvent) is a high frequency event,\n" + - "it may be called thousands of times per a second on a busy server.\n" + - "Where possible the event may also only be called for the \"root\" block of\n" + - "physics updates in order to limit event spam.\n" + - "Physics updates that cause other blocks to change their state may not result\n" + - "in an event for each of those blocks (usually adjacent)."); - this.limit = config.getInt(configPath + ".block-physics-event-limit", 256000, - "Maximum number of times a physics check can be performed within the configured\n" + - "timeframe before they will be put on cooldown."); + "to help reduce lag by cancelling burst activity hotspots.\n" + + "\n" + + "Note:\n" + + "\n" + + "The event used for this check (BlockPhysicsEvent) is a high frequency event,\n" + + "it may be called thousands of times per a second on a busy server.\n" + + "Where possible the event may also only be called for the \"root\" block of\n" + + "physics updates in order to limit event spam.\n" + + "Physics updates that cause other blocks to change their state may not result\n" + + "in an event for each of those blocks (usually adjacent)." + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPhysics(BlockPhysicsEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntitySpawns.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntitySpawns.java index ea98637a3..da0c99aca 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntitySpawns.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntitySpawns.java @@ -1,24 +1,27 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XEntityType; +import me.xginko.aef.utils.GenericUtil; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntitySpawnEvent; -public class EntitySpawns extends RegionalActivityModule { - - private final int limit; +public class EntitySpawns extends RegionalEntityActivityModule { public EntitySpawns() { super( "creature-spawn", + false, true, + 6000, 1500.0, 18000, 20000, 10.0, - 120.0 - ); - this.config.addComment(configPath + ".enable", + 120.0, + GenericUtil.mapOfEntries( + GenericUtil.mapEntry(XEntityType.WITHER, 50), + GenericUtil.mapEntry(XEntityType.WITHER_SKULL, 200)), "Limits entity spawning activity within a configurable radius and timeframe\n" + "to help reduce lag by cancelling high activity hotspots.\n" + "\n" + @@ -26,14 +29,13 @@ public EntitySpawns() { "\n" + "- A creature gets spawned naturally, by spawner or other reasons.\n" + "- An entity gets spawned naturally, by spawner or other reasons.\n" + - "This does not include tile entities."); - this.limit = config.getInt(configPath + ".spawn-event-limit", 6000, - "Maximum number of entity spawns within configured timeframe."); + "This does not include tile entities." + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntitySpawn(EntitySpawnEvent event) { - if (shouldCancelActivity(event, event.getLocation(), limit)) { + if (shouldCancelEntityEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntityTargeting.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntityTargeting.java index 7e15a79f1..53ca8b03b 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntityTargeting.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/EntityTargeting.java @@ -2,13 +2,11 @@ import com.cryptomorin.xseries.XEntityType; import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.utils.GenericUtil; import me.xginko.aef.utils.LocationUtil; -import org.bukkit.Location; -import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.util.NumberConversions; @@ -16,28 +14,26 @@ import java.util.Map; import java.util.TreeMap; -public class EntityTargeting extends RegionalActivityModule implements Listener { +public class EntityTargeting extends RegionalEntityActivityModule { - private final Map limitedTypes = new EnumMap<>(EntityType.class); + private final Map typedDistanceLimits = new EnumMap<>(EntityType.class); private final double globalMaxDistanceSquared; - private final int limit; private final boolean globalDistanceEnabled, perTypeDistanceEnabled; public EntityTargeting() { super("entity-targeting", + false, true, + 8000, 1500.0, 18000, 20000, 14.0, - 120.0 - ); - this.config.addComment(configPath+".enable", + 120.0, + GenericUtil.mapOfEntries(GenericUtil.mapEntry(XEntityType.VILLAGER, 1000)), "Limits entities targeting other entities within a configurable radius\n" + - "and timeframe to help reduce lag by cancelling burst activity hotspots."); - this.limit = config.getInt(configPath + ".entity-target-event-limit", 8000, - "Maximum number of times an entity can target another entity within the\n" + - "configured timeframe before the area will be put on cooldown."); + "and timeframe to help reduce lag by cancelling burst activity hotspots." + ); this.globalDistanceEnabled = config.getBoolean(configPath + ".distance-limit.global-limit.enable", false); this.globalMaxDistanceSquared = NumberConversions.square( @@ -65,7 +61,7 @@ public EntityTargeting() { try { Double maxDistanceSquared = NumberConversions.square(Double.parseDouble(section.getString(configuredEntity))); EntityType limitedEntity = EntityType.valueOf(configuredEntity); - this.limitedTypes.put(limitedEntity, maxDistanceSquared); + this.typedDistanceLimits.put(limitedEntity, maxDistanceSquared); } catch (NumberFormatException e) { notRecognized(Double.class, configuredEntity); } catch (IllegalArgumentException e) { @@ -76,11 +72,9 @@ public EntityTargeting() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityTarget(EntityTargetEvent event) { - Entity targetEntity = event.getTarget(); - if (targetEntity == null) return; // If entity un-targets an entity, it's good for us. + if (event.getTarget() == null) return; // If entity un-targets an entity, it's good for us. - Location location = event.getEntity().getLocation(); - if (shouldCancelActivity(event, location, limit)) { + if (shouldCancelEntityEvent(event)) { event.setCancelled(true); return; } @@ -91,7 +85,7 @@ private void onEntityTarget(EntityTargetEvent event) { double targetDistanceSquared; try { - targetDistanceSquared = event.getEntity().getLocation().distanceSquared(targetEntity.getLocation()); + targetDistanceSquared = event.getEntity().getLocation().distanceSquared(event.getTarget().getLocation()); } catch (IllegalArgumentException e) { if (logIsEnabled) error("Unable to measure distance between entity and target.", e); return; @@ -102,18 +96,18 @@ private void onEntityTarget(EntityTargetEvent event) { event.setCancelled(true); event.setTarget(null); if (logIsEnabled) info("Cancelled target acquire for entity " + event.getEntityType().name() + " at " + - LocationUtil.toString(location) + + LocationUtil.toString(event.getTarget().getLocation()) + " because target is further than the global limit. Distance: " + Math.sqrt(targetDistanceSquared)); return; } } if (perTypeDistanceEnabled) { - if (limitedTypes.containsKey(event.getEntityType()) && targetDistanceSquared > limitedTypes.get(event.getEntityType())) { + if (typedDistanceLimits.containsKey(event.getEntityType()) && targetDistanceSquared > typedDistanceLimits.get(event.getEntityType())) { event.setCancelled(true); event.setTarget(null); if (logIsEnabled) info("Cancelled target acquire for entity " + event.getEntityType().name() + " at " + - LocationUtil.toString(location) + + LocationUtil.toString(event.getTarget().getLocation()) + " because target further than its configured limit. Distance: " + Math.sqrt(targetDistanceSquared)); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Explosions.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Explosions.java index d9a232bdd..f860c8794 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Explosions.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Explosions.java @@ -8,49 +8,45 @@ public class Explosions extends RegionalActivityModule { - private final int limit; - public Explosions() { super( "explosions", false, + true, + 1000, 1500.0, 6000, 10000, 10.0, - 120.0 - ); - this.config.addComment(configPath + ".enable", + 120.0, "Limits explosions within a configurable radius and timeframe\n" + - "to help reduce lag by cancelling high activity hotspots.\n" + - "\n" + - "Examples:\n" + - "\n" + - "- A block exploding.\n" + - "- An entity exploding.\n" + - "- An entity making the decision to explode.\n"); - this.limit = config.getInt(configPath + ".explode-event-limit", 500, - "Maximum number of explode events within the configured timeframe\n" + - "before the region will be put on cooldown."); + "to help reduce lag by cancelling high activity hotspots.\n" + + "\n" + + "Examples:\n" + + "\n" + + "- A block exploding.\n" + + "- An entity exploding.\n" + + "- An entity making the decision to explode.\n" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onExplosionPrime(ExplosionPrimeEvent event) { - if (shouldCancelActivity(event, event.getEntity().getLocation(), limit)) { + if (shouldCancelEvent(event, event.getEntity().getLocation())) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityExplode(EntityExplodeEvent event) { - if (shouldCancelActivity(event, event.getLocation(), limit)) { + if (shouldCancelEvent(event, event.getEntity().getLocation())) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockExplode(BlockExplodeEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelEvent(event, event.getBlock().getLocation())) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/LiquidSpread.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/LiquidSpread.java index 37d94c326..b2d57f4a1 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/LiquidSpread.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/LiquidSpread.java @@ -1,45 +1,41 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.GenericUtil; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFromToEvent; -public class LiquidSpread extends RegionalActivityModule { - - private final int limit; - private final boolean ignoreDragonEgg; +public class LiquidSpread extends RegionalBlockActivityModule { public LiquidSpread() { super( "liquid-spread", + false, true, + 2400, 1500.0, 18000, 20000, 12.0, - 100.0 - ); - this.config.addComment(configPath+".enable", + 100.0, + GenericUtil.mapOfEntries( + GenericUtil.mapEntry(XMaterial.WATER, 4000), + GenericUtil.mapEntry(XMaterial.LAVA, 6000)), "Limits liquid spreading within a configurable radius and timeframe\n" + - "to help reduce lag by cancelling high activity hotspots.\n" + - "\n" + - "Examples:\n" + - "\n" + - "- A lava block spreading by flowing.\n" + - "- A water block spreading by flowing.\n" + - "- (optional) A dragon egg is teleporting from one position to another."); - this.limit = config.getInt(configPath + ".liquid-spread-event-limit", 2400, - "Maximum number of times liquids are allowed to spread within the configured\n" + - "timeframe before they will be put on cooldown."); - this.ignoreDragonEgg = config.getBoolean(configPath + ".ignore-dragon-egg", true); + "to help reduce lag by cancelling high activity hotspots.\n" + + "\n" + + "Examples:\n" + + "\n" + + "- A lava block spreading by flowing.\n" + + "- A water block spreading by flowing.\n" + + "- (optional) A dragon egg is teleporting from one position to another." + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockFromTo(BlockFromToEvent event) { - if (ignoreDragonEgg && event.getBlock().getType() == XMaterial.DRAGON_EGG.parseMaterial()) return; - - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Noteblocks.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Noteblocks.java deleted file mode 100755 index 22c976582..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Noteblocks.java +++ /dev/null @@ -1,40 +0,0 @@ -package me.xginko.aef.modules.lagpreventions.regionalactivity; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.NotePlayEvent; - -public class Noteblocks extends RegionalActivityModule { - - private final int limit; - - public Noteblocks() { - super( - "noteblocks", - false, - 1500.0, - 6000, - 10000, - 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", - "Limits noteblocks being played within a configurable radius and timeframe\n" + - "to help reduce lag by cancelling high activity hotspots.\n" + - "\n" + - "Examples:\n" + - "\n" + - "- A noteblock is being played through player interaction.\n" + - "- A noteblock is being played through a redstone current.\n"); - this.limit = config.getInt(configPath + ".noteblock-play-limit", 2800, - "Maximum number of times a noteblock can be played within the configured\n" + - "timeframe before they will be put on cooldown."); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onNotePlay(NotePlayEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { - event.setCancelled(true); - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pathfinding.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pathfinding.java index 5e96bb85e..eb5d7c9e8 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pathfinding.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pathfinding.java @@ -3,42 +3,39 @@ import com.cryptomorin.xseries.XEntityType; import com.destroystokyo.paper.event.entity.EntityPathfindEvent; import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.utils.GenericUtil; import me.xginko.aef.utils.LocationUtil; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; import org.bukkit.util.NumberConversions; import java.util.EnumMap; import java.util.Map; import java.util.TreeMap; -public class Pathfinding extends RegionalActivityModule implements Listener { +public class Pathfinding extends RegionalEntityActivityModule { - private final Map limitedTypes = new EnumMap<>(EntityType.class); + private final Map typedDistanceLimits = new EnumMap<>(EntityType.class); private final double globalMaxDistanceSquared; - private final int limit; private final boolean globalDistanceEnabled, perTypeDistanceEnabled; public Pathfinding() { super( "entity-pathfinding", false, + true, + 4000, 1500.0, 6000, 10000, 14.0, - 120.0 - ); - this.config.addComment(configPath+".enable", + 120.0, + GenericUtil.mapOfEntries(GenericUtil.mapEntry(XEntityType.VILLAGER, 1000)), "Limits entities deciding to pathfind to a specific location\n" + "within a configurable radius and timeframe to help reduce lag\n" + - "by cancelling burst activity hotspots."); - this.limit = config.getInt(configPath + ".entity-pathfind-event-limit", 4000, - "Maximum number of times an entity can decide to start moving\n" + - "towards a location within the configured timeframe before the\n" + - "area will be put on cooldown."); + "by cancelling burst activity hotspots." + ); this.globalDistanceEnabled = config.getBoolean(configPath + ".distance-limit.global-limit.enable", false); this.globalMaxDistanceSquared = NumberConversions.square( @@ -66,7 +63,7 @@ public Pathfinding() { try { Double maxDistanceSquared = NumberConversions.square(Double.parseDouble(section.getString(configuredEntity))); EntityType limitedEntity = EntityType.valueOf(configuredEntity); - this.limitedTypes.put(limitedEntity, maxDistanceSquared); + this.typedDistanceLimits.put(limitedEntity, maxDistanceSquared); } catch (NumberFormatException e) { notRecognized(Double.class, configuredEntity); } catch (IllegalArgumentException e) { @@ -77,7 +74,7 @@ public Pathfinding() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onEntityPathfind(EntityPathfindEvent event) { - if (shouldCancelActivity(event, event.getEntity().getLocation(), limit)) { + if (shouldCancelEntityEvent(event)) { event.setCancelled(true); return; } @@ -105,7 +102,7 @@ private void onEntityPathfind(EntityPathfindEvent event) { } if (perTypeDistanceEnabled) { - if (limitedTypes.containsKey(event.getEntityType()) && targetDistanceSquared > limitedTypes.get(event.getEntityType())) { + if (typedDistanceLimits.containsKey(event.getEntityType()) && targetDistanceSquared > typedDistanceLimits.get(event.getEntityType())) { event.setCancelled(true); if (logIsEnabled) info("Cancelled pathfinding for entity " + event.getEntityType() + " at " + LocationUtil.toString(event.getEntity().getLocation()) + diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pistons.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pistons.java index 7d6277102..67766e587 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pistons.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Pistons.java @@ -1,47 +1,48 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.GenericUtil; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; -public class Pistons extends RegionalActivityModule { - - private final int limit; +public class Pistons extends RegionalBlockActivityModule { public Pistons() { super( "pistons", false, + true, + 2000, 1500.0, 6000, 10000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", + 120.0, + GenericUtil.mapOfEntries( + GenericUtil.mapEntry(XMaterial.PISTON, 1000), + GenericUtil.mapEntry(XMaterial.STICKY_PISTON, 1000)), "Limits piston movement within a configurable radius and timeframe\n" + - "to help reduce lag by cancelling high activity hotspots.\n" + - "\n" + - "Examples:\n" + - "\n" + - "- A piston extends.\n" + - "- A piston retracts.\n"); - this.limit = config.getInt(configPath + ".piston-movement-limit", 1000, - "Maximum number of piston extend and/or retracts within the\n" + - "configured timeframe."); + "to help reduce lag by cancelling high activity hotspots.\n" + + "\n" + + "Examples:\n" + + "\n" + + "- A piston extends.\n" + + "- A piston retracts.\n" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPistonExtend(BlockPistonExtendEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPistonRetract(BlockPistonRetractEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Redstone.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Redstone.java index e694414ec..316a079d3 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Redstone.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/Redstone.java @@ -1,39 +1,44 @@ package me.xginko.aef.modules.lagpreventions.regionalactivity; +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.utils.GenericUtil; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockRedstoneEvent; -public class Redstone extends RegionalActivityModule { - - private final int limit; +public class Redstone extends RegionalBlockActivityModule { public Redstone() { super( "redstone", + false, true, + 6000, 1500.0, 18000, 20000, 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", + 120.0, + GenericUtil.mapOfEntries( + GenericUtil.mapEntry(XMaterial.SCULK_SENSOR, 500), + GenericUtil.mapEntry(XMaterial.SCULK_SHRIEKER, 300), + GenericUtil.mapEntry(XMaterial.CALIBRATED_SCULK_SENSOR, 500), + GenericUtil.mapEntry(XMaterial.OBSERVER, 1500), + GenericUtil.mapEntry(XMaterial.COMPARATOR, 2000)), "Limits redstone activity within a configurable radius and timeframe\n" + - "to help reduce lag by cancelling high activity hotspots.\n" + - "\n" + - "Examples:\n" + - "\n" + - "- A redstone current changes.\n" + - "- A redstone block gets powered on.\n" + - "- A redstone block gets powered off.\n"); - this.limit = config.getInt(configPath + ".redstone-event-limit", 6000, - "Maximum number of redstone events within configured timeframe."); + "to help reduce lag by cancelling high activity hotspots.\n" + + "\n" + + "Examples:\n" + + "\n" + + "- A redstone current changes.\n" + + "- A redstone block gets powered on.\n" + + "- A redstone block gets powered off.\n" + ); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockRedstone(BlockRedstoneEvent event) { - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { + if (shouldCancelBlockEvent(event)) { event.setNewCurrent(0); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalActivityModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalActivityModule.java index 35c48e74d..ca16d65a6 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalActivityModule.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalActivityModule.java @@ -4,14 +4,19 @@ import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.models.BlockRegion2D; +import me.xginko.aef.utils.models.Lazy; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; import java.time.Duration; +import java.util.EnumMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -22,110 +27,148 @@ */ public abstract class RegionalActivityModule extends AEFModule implements Listener { - protected final Cache regionDataCache; - protected final long pauseTimeMillis; + protected final long cacheTimeMillis, pauseTimeMillis; protected final double checkRadius, pauseTPS, pauseMSPT; + protected final int totalActivityLimit; protected final boolean logIsEnabled; + protected Cache regionDataCache; + public RegionalActivityModule( - String subConfigPath, boolean deflogEnabled, double defCheckRadius, + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, double defCheckRadius, int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT ) { - super("lag-preventions.regional-activity."+subConfigPath); - String configPath = "lag-preventions.regional-activity."+subConfigPath; + this(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, + defPauseMillis, defCacheMillis, defPauseTPS, defPauseMSPT, null); + } + + public RegionalActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int defTotalLimit, double defCheckRadius, + int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, String comment) { + super("lag-preventions.regional-activity."+subConfigPath, defEnabled, comment); + String configPath = "lag-preventions.regional-activity." + subConfigPath; this.logIsEnabled = config.getBoolean(configPath + ".log", deflogEnabled); + this.totalActivityLimit = config.getInt(configPath + ".total-limit", defTotalLimit, + "The maximum amount of measured activity of this type that is allowed\n" + + "to happen within the configured timeframe (cache-millis).\n" + + "This value should always be higher than any of the configured per type limits."); this.checkRadius = config.getDouble(configPath + ".check-radius-blocks", defCheckRadius, "The radius in blocks in which activity will be grouped together and measured."); this.pauseTimeMillis = config.getInt(configPath + ".pause-time-millis", defPauseMillis, "The time in milliseconds all related activity will be blocked if it exceeded\n" + "the configured limit."); - this.regionDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis( - config.getInt(configPath + ".data-keep-time-millis", defCacheMillis, - "The time in milliseconds before a region and its data will be expired\n" + - "if no activity has been detected.\n" + - "For proper functionality, needs to be at least as long as your pause time."))).build(); + this.cacheTimeMillis = Math.max(100L, config.getInt(configPath + ".data-keep-time-millis", defCacheMillis, + "The time in milliseconds before a region and its data will be expired\n" + + "if no activity has been detected.\n" + + "For proper functionality, needs to be at least as long as your pause time.")); this.pauseTPS = config.getDouble(configPath + ".pause-TPS", defPauseTPS, "The TPS at which to cancel the physics entirely."); this.pauseMSPT = config.getDouble(configPath + ".pause-MSPT", defPauseMSPT, "The MSPT at which to cancel the physics entirely."); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void enable() { + regionDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } @Override public void disable() { HandlerList.unregisterAll(this); - regionDataCache.invalidateAll(); + if (regionDataCache != null) { + regionDataCache.invalidateAll(); + regionDataCache.cleanUp(); + regionDataCache = null; + } + } + + protected @NotNull BlockRegion2D getRegion(Location location) { + // Find and return region containing this location + for (Map.Entry regionDataEntry : regionDataCache.asMap().entrySet()) { + if (regionDataEntry.getKey().contains(location)) { + return regionDataEntry.getKey(); + } + } + // Create and cache region if none exists + BlockRegion2D region = BlockRegion2D.of(location.getWorld(), location.getX(), location.getZ(), checkRadius); + regionDataCache.put(region, new RegionData(region)); + return region; } - @SuppressWarnings("DataFlowIssue") protected @NotNull RegionalActivityModule.RegionData getRegionData(Location location) { return regionDataCache.get(getRegion(location), RegionData::new); } - public boolean shouldCancelActivity(Event event, Location location, int limit) { - double tps = AnarchyExploitFixes.getTickReporter().getTPS(); - double mspt = AnarchyExploitFixes.getTickReporter().getMSPT(); + protected boolean shouldCancelEvent(T event, Location location) { + return shouldCancelBecauseLagging(event) || shouldCancelBecauseTotalActivity(event, location); + } - if (tps <= pauseTPS || mspt >= pauseMSPT) { + protected boolean shouldCancelBecauseLagging(T event) { + double ticksPerSecond = AnarchyExploitFixes.tickReporter().getTPS(); + double milliSecondsPerTick = AnarchyExploitFixes.tickReporter().getMSPT(); + if (ticksPerSecond <= pauseTPS || milliSecondsPerTick >= pauseMSPT) { if (logIsEnabled) info("Cancelling " + event.getClass().getSimpleName() + " because server is lagging." + - " (tps="+String.format("%.4f", tps)+" | mspt="+String.format("%.4f", mspt)+")"); + " (tps="+String.format("%.4f", ticksPerSecond)+" | mspt="+String.format("%.4f", milliSecondsPerTick)+")"); return true; } + return false; + } + protected boolean shouldCancelBecauseTotalActivity(T event, Location location) { RegionData regionData = getRegionData(location); - if (regionData.resumeTime.get() > System.currentTimeMillis()) { + if (regionData.getTotalActivityData().resumeTimeMillis.get() > System.currentTimeMillis()) { + if (logIsEnabled) info("Cancelling " + event.getClass().getSimpleName() + " indiscriminately at " + + LocationUtil.toString(location) + " because the region exceeded the total activity limit."); return true; } - if (regionData.activityCount.incrementAndGet() > limit) { + if (regionData.getTotalActivityData().activityCount.incrementAndGet() > totalActivityLimit) { if (logIsEnabled) { info( "Disabling in a radius of " + checkRadius + " blocks from center at " + "x=" + regionData.region.getCenterX() + ", z=" + regionData.region.getCenterZ() + " in world " + location.getWorld().getName() + " for " + pauseTimeMillis + "ms, " + "because of too high activity within the configured timeframe: " + - regionData.activityCount + " (limit: " + limit + ")"); + regionData.getTotalActivityData().activityCount + " (limit: " + totalActivityLimit + ")"); } - regionData.resumeTime.set(System.currentTimeMillis() + pauseTimeMillis); - regionData.activityCount.set(0); // Reset count when region is cooling down + regionData.getTotalActivityData().resumeTimeMillis.set(System.currentTimeMillis() + pauseTimeMillis); + regionData.getTotalActivityData().activityCount.set(0); // Reset count when region is cooling down return true; } return false; } - public @NotNull BlockRegion2D getRegion(Location location) { - // Find and return region containing this location - for (Map.Entry regionDataEntry : regionDataCache.asMap().entrySet()) { - if (regionDataEntry.getKey().contains(location)) { - return regionDataEntry.getKey(); - } - } - // Create and cache region if none exists - BlockRegion2D region = BlockRegion2D.of(location.getWorld(), location.getX(), location.getZ(), checkRadius); - regionDataCache.put(region, new RegionData(region)); - return region; - } - protected static class RegionData { public final BlockRegion2D region; - public final AtomicLong resumeTime; - public final AtomicInteger activityCount; + private final ActivityData totalActivityData; + private final Lazy> blockActivityData; + private final Lazy> entityActivityData; public RegionData(BlockRegion2D region) { this.region = region; - this.activityCount = new AtomicInteger(0); - this.resumeTime = new AtomicLong(0L); + this.totalActivityData = new ActivityData(); + this.blockActivityData = Lazy.of(() -> new EnumMap<>(Material.class)); + this.entityActivityData = Lazy.of(() -> new EnumMap<>(EntityType.class)); + } + + public ActivityData getTotalActivityData() { + return totalActivityData; + } + + public ActivityData getBlockActivityData(Material material) { + return blockActivityData.get().computeIfAbsent(material, k -> new ActivityData()); + } + + public ActivityData getEntityActivityData(EntityType entityType) { + return entityActivityData.get().computeIfAbsent(entityType, k -> new ActivityData()); + } + + public static class ActivityData { + public final AtomicInteger activityCount = new AtomicInteger(); + public final AtomicLong resumeTimeMillis = new AtomicLong(); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalBlockActivityModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalBlockActivityModule.java new file mode 100644 index 000000000..1dead490f --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalBlockActivityModule.java @@ -0,0 +1,93 @@ +package me.xginko.aef.modules.lagpreventions.regionalactivity; + +import com.cryptomorin.xseries.XMaterial; +import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.utils.LocationUtil; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.event.block.BlockEvent; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +/** + * Credits to the initial idea of measuring burst activity within a certain region + * of the world go to kumori (Soft1k) of 3b3t.org. + */ +public abstract class RegionalBlockActivityModule extends RegionalActivityModule { + + protected final Map typedActivityLimit = new EnumMap<>(Material.class); + + public RegionalBlockActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, double defCheckRadius, + int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, + Map defaultTypeSettings + ) { + this(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, defPauseMillis, defCacheMillis, + defPauseTPS, defPauseMSPT, defaultTypeSettings, null); + } + + public RegionalBlockActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, + double defCheckRadius, int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, + Map defaultTypeSettings, String comment) { + super(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, defPauseMillis, defCacheMillis, defPauseTPS, defPauseMSPT, comment); + Map defaultKV = new HashMap<>(defaultTypeSettings.size()); + for (Map.Entry entry : defaultTypeSettings.entrySet()) { + if (entry.getKey().isSupported()) { + defaultKV.put(entry.getKey().get().name(), entry.getValue()); + } + } + ConfigSection typedSection = config.getConfigSection(configPath + ".typed-limits", defaultKV, + "Set activity limits per Material (BlockType)." + + "Note that you cannot set a value higher than the one configured in total-limit."); + for (String configuredMaterial : typedSection.getKeys(false)) { + try { + typedActivityLimit.put(Material.valueOf(configuredMaterial), Integer.parseInt(typedSection.getString(configuredMaterial))); + } catch (NumberFormatException e) { + notRecognized(Integer.class, typedSection.getString(configuredMaterial)); + }catch (IllegalArgumentException e) { + notRecognized(GameMode.class, configuredMaterial); + } + } + } + + protected boolean shouldCancelBlockEvent(T blockEvent) { + return shouldCancelEvent(blockEvent, blockEvent.getBlock().getLocation()) || shouldCancelBecauseTypeActivity(blockEvent); + } + + protected boolean shouldCancelBecauseTypeActivity(T blockEvent) { + if (!typedActivityLimit.containsKey(blockEvent.getBlock().getType())) { + return false; + } + + int typeLimit = typedActivityLimit.get(blockEvent.getBlock().getType()); + RegionData regionData = getRegionData(blockEvent.getBlock().getLocation()); + RegionData.ActivityData activityData = regionData.getBlockActivityData(blockEvent.getBlock().getType()); + + if (activityData.resumeTimeMillis.get() > System.currentTimeMillis()) { + if (logIsEnabled) { + info( "Cancelling " + blockEvent.getClass().getSimpleName() + " for " + blockEvent.getBlock().getType().name() + + " at " + LocationUtil.toString(blockEvent.getBlock().getLocation()) + " because it exceeded its " + + "activity (limit: " + typeLimit + ")."); + } + return true; + } + + if (activityData.activityCount.incrementAndGet() > typeLimit) { + if (logIsEnabled) { + warn( "Disabling " + blockEvent.getBlock().getType().name() + " in a radius of " + checkRadius + + " blocks from center at x=" + regionData.region.getCenterX() + ", z=" + regionData.region.getCenterZ() + + " in world " + blockEvent.getBlock().getWorld().getName() + " for " + pauseTimeMillis + + "ms, because of too high activity within the configured timeframe: " + + activityData.activityCount + " (limit: " + typeLimit + ")"); + } + activityData.resumeTimeMillis.set(System.currentTimeMillis() + pauseTimeMillis); + activityData.activityCount.set(0); // Reset count when region is cooling down + return true; + } + + return false; + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalEntityActivityModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalEntityActivityModule.java new file mode 100644 index 000000000..fbc06470c --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/RegionalEntityActivityModule.java @@ -0,0 +1,93 @@ +package me.xginko.aef.modules.lagpreventions.regionalactivity; + +import com.cryptomorin.xseries.XEntityType; +import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.utils.LocationUtil; +import org.bukkit.GameMode; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.EntityEvent; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +/** + * Credits to the initial idea of measuring burst activity within a certain region + * of the world go to kumori (Soft1k) of 3b3t.org. + */ +public abstract class RegionalEntityActivityModule extends RegionalActivityModule { + + protected final Map typedActivityLimit = new EnumMap<>(EntityType.class); + + public RegionalEntityActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, double defCheckRadius, + int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, + Map defaultTypeSettings + ) { + this(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, defPauseMillis, defCacheMillis, + defPauseTPS, defPauseMSPT, defaultTypeSettings, null); + } + + public RegionalEntityActivityModule( + String subConfigPath, boolean defEnabled, boolean deflogEnabled, int totalLimit, + double defCheckRadius, int defPauseMillis, int defCacheMillis, double defPauseTPS, double defPauseMSPT, + Map defaultTypeSettings, String comment) { + super(subConfigPath, defEnabled, deflogEnabled, totalLimit, defCheckRadius, defPauseMillis, defCacheMillis, defPauseTPS, defPauseMSPT, comment); + Map defaultKV = new HashMap<>(defaultTypeSettings.size()); + for (Map.Entry entry : defaultTypeSettings.entrySet()) { + if (entry.getKey().isSupported()) { + defaultKV.put(entry.getKey().get().name(), entry.getValue()); + } + } + ConfigSection typedSection = config.getConfigSection(configPath + ".typed-limits", defaultKV, + "Set activity limits per EntityType." + + "Note that you cannot set a value higher than the one configured in total-limit."); + for (String configuredEntity : typedSection.getKeys(false)) { + try { + typedActivityLimit.put(EntityType.valueOf(configuredEntity), Integer.parseInt(typedSection.getString(configuredEntity))); + } catch (NumberFormatException e) { + notRecognized(Integer.class, typedSection.getString(configuredEntity)); + }catch (IllegalArgumentException e) { + notRecognized(GameMode.class, configuredEntity); + } + } + } + + protected boolean shouldCancelEntityEvent(T entityEvent) { + return shouldCancelEvent(entityEvent, entityEvent.getEntity().getLocation()) || shouldCancelBecauseTypeActivity(entityEvent); + } + + protected boolean shouldCancelBecauseTypeActivity(T entityEvent) { + if (!typedActivityLimit.containsKey(entityEvent.getEntity().getType())) { + return false; + } + + int typeLimit = typedActivityLimit.get(entityEvent.getEntityType()); + RegionData regionData = getRegionData(entityEvent.getEntity().getLocation()); + RegionData.ActivityData activityData = regionData.getEntityActivityData(entityEvent.getEntityType()); + + if (activityData.resumeTimeMillis.get() > System.currentTimeMillis()) { + if (logIsEnabled) { + info( "Cancelling " + entityEvent.getClass().getSimpleName() + " for " + entityEvent.getEntityType().name() + + " at " + LocationUtil.toString(entityEvent.getEntity().getLocation()) + " because it exceeded its " + + "activity (limit: " + typeLimit + ")."); + } + return true; + } + + if (activityData.activityCount.incrementAndGet() > typeLimit) { + if (logIsEnabled) { + warn( "Disabling " + entityEvent.getEntityType().name() + " in a radius of " + checkRadius + + " blocks from center at x=" + regionData.region.getCenterX() + ", z=" + regionData.region.getCenterZ() + + " in world " + entityEvent.getEntity().getWorld().getName() + " for " + pauseTimeMillis + "ms, " + + "because of too high activity within the configured timeframe: " + + activityData.activityCount + " (limit: " + typeLimit + ")"); + } + activityData.resumeTimeMillis.set(System.currentTimeMillis() + pauseTimeMillis); + activityData.activityCount.set(0); // Reset count when region is cooling down + return true; + } + + return false; + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkActivity.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkActivity.java deleted file mode 100644 index 0d4896f80..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/regionalactivity/SculkActivity.java +++ /dev/null @@ -1,79 +0,0 @@ -package me.xginko.aef.modules.lagpreventions.regionalactivity; - -import com.cryptomorin.xseries.XMaterial; -import org.bukkit.Material; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockPhysicsEvent; -import org.bukkit.event.block.BlockRedstoneEvent; - -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class SculkActivity extends RegionalActivityModule { - - private final Set sculkBlocks; - private final int limit; - - public SculkActivity() { - super( - "sculk-sensor", - true, - 1500.0, - 18000, - 20000, - 10.0, - 120.0 - ); - this.config.addComment(configPath+".enable", - "Limits sculk activity within a configurable radius and timeframe\n" + - "to help reduce lag by cancelling high activity hotspots.\n" + - "\n" + - "Examples:\n" + - "\n" + - "- A redstone current changes for a sculk sensor.\n" + - "- A physics check is being performed for a sculk sensor."); - this.limit = config.getInt(configPath + ".sculk-event-limit", 800, - "Maximum number of sculk events within configured timeframe."); - List defaults = Stream.of( - XMaterial.SCULK_SENSOR, - XMaterial.SCULK_SHRIEKER, - XMaterial.CALIBRATED_SCULK_SENSOR) - .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) - .map(Enum::name) - .collect(Collectors.toList()); - this.sculkBlocks = config.getList(configPath + ".sculk-blocks", defaults) - .stream() - .map(configuredType -> { - try { - return Material.valueOf(configuredType); - } catch (IllegalArgumentException e) { - notRecognized(Material.class, configuredType); - return null; - } - }) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockRedstone(BlockRedstoneEvent event) { - if (!sculkBlocks.contains(event.getBlock().getType())) return; - - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { - event.setNewCurrent(0); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockPhysics(BlockPhysicsEvent event) { - if (!sculkBlocks.contains(event.getBlock().getType())) return; - - if (shouldCancelActivity(event, event.getBlock().getLocation(), limit)) { - event.setCancelled(true); - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/FirstJoinMessages.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/FirstJoinMessages.java index 4cbd07fe5..f0bc76543 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/FirstJoinMessages.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/FirstJoinMessages.java @@ -1,7 +1,7 @@ package me.xginko.aef.modules.misc; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -19,12 +19,11 @@ public class FirstJoinMessages extends AEFModule implements Listener { private final boolean logFirstJoin; public FirstJoinMessages() { - super("misc.join-leave-messages.first-join-messages"); - this.totalPlayers = new AtomicInteger(0); - this.config.addComment(configPath + ".enable", + super("misc.join-leave-messages.first-join-messages", false, "Configure message in lang folder.\n" + - "You can hide yourself and other players using the permission:\n" + - AEFPermission.SILENT_JOIN.string()); + "You can hide yourself and other players using the permission:\n" + + AEFPermission.SILENT_JOIN.node()); + this.totalPlayers = new AtomicInteger(0); this.logFirstJoin = config.getBoolean(configPath + ".show-in-console", true); } @@ -37,11 +36,6 @@ public void enable() { .thenRun(() -> plugin.getServer().getPluginManager().registerEvents(this, plugin)); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -51,12 +45,12 @@ public void disable() { private void onPlayerJoin(PlayerJoinEvent event) { final Player joiningPlayer = event.getPlayer(); if (joiningPlayer.hasPlayedBefore()) return; - if (joiningPlayer.hasPermission(AEFPermission.SILENT_JOIN.string())) return; + if (AnarchyExploitFixes.permissions().permissionValue(joiningPlayer, AEFPermission.SILENT_JOIN.node()).toBoolean()) return; final int playersNumber = totalPlayers.incrementAndGet(); for (final Player onlinePlayer : plugin.getServer().getOnlinePlayers()) { - AnarchyExploitFixes.getDatastore().getJoinLeaveEnabled(onlinePlayer.getUniqueId()).thenAccept(enabled -> { + AnarchyExploitFixes.datastore().getJoinLeaveEnabled(onlinePlayer.getUniqueId()).thenAccept(enabled -> { if (enabled) AnarchyExploitFixes.getLang(onlinePlayer.getLocale()).misc_firstJoinMessage. forEach(line -> onlinePlayer.sendMessage(line .replace("%player%", joiningPlayer.getName()) diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/JoinLeaveMessages.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/JoinLeaveMessages.java index 4d92756ff..4b495685f 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/JoinLeaveMessages.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/JoinLeaveMessages.java @@ -1,7 +1,7 @@ package me.xginko.aef.modules.misc; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -16,11 +16,10 @@ public class JoinLeaveMessages extends AEFModule implements Listener { private final boolean showInConsole, firstJoinEnabled; public JoinLeaveMessages() { - super("misc.join-leave-messages"); - config.addComment(configPath + ".enable", + super("misc.join-leave-messages", false, "If you want to hide yourself or someone else when logging\n" + - "into the game, use these permissions:\n" + - AEFPermission.SILENT_JOIN.string() + ", " + AEFPermission.SILENT_LEAVE.string()); + "into the game, use these permissions:\n" + + AEFPermission.SILENT_JOIN.node() + ", " + AEFPermission.SILENT_LEAVE.node()); this.showInConsole = config.getBoolean(configPath + ".show-in-console", false); this.firstJoinEnabled = config.getBoolean(configPath + ".first-join-messages.enable", false); } @@ -30,11 +29,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -44,11 +38,11 @@ public void disable() { private void onPlayerJoinEvent(PlayerJoinEvent event) { event.setJoinMessage(null); final Player joiningPlayer = event.getPlayer(); - if (joiningPlayer.hasPermission(AEFPermission.SILENT_JOIN.string())) return; + if (AnarchyExploitFixes.permissions().permissionValue(joiningPlayer, AEFPermission.SILENT_JOIN.node()).toBoolean()) return; if (firstJoinEnabled && !joiningPlayer.hasPlayedBefore()) return; for (final Player onlinePlayer : plugin.getServer().getOnlinePlayers()) { - AnarchyExploitFixes.getDatastore().getJoinLeaveEnabled(onlinePlayer.getUniqueId()).thenAccept(enabled -> { + AnarchyExploitFixes.datastore().getJoinLeaveEnabled(onlinePlayer.getUniqueId()).thenAccept(enabled -> { if (enabled) { onlinePlayer.sendMessage(AnarchyExploitFixes.getLang(onlinePlayer.getLocale()).misc_joinMessage .replace("%player%", joiningPlayer.getName())); @@ -65,11 +59,11 @@ private void onPlayerJoinEvent(PlayerJoinEvent event) { private void onPlayerLeaveEvent(PlayerQuitEvent event) { event.setQuitMessage(null); final Player leavingPlayer = event.getPlayer(); - if (leavingPlayer.hasPermission(AEFPermission.SILENT_LEAVE.string())) return; + if (AnarchyExploitFixes.permissions().permissionValue(leavingPlayer, AEFPermission.SILENT_LEAVE.node()).toBoolean()) return; for (final Player onlinePlayer : plugin.getServer().getOnlinePlayers()) { if (onlinePlayer.getUniqueId().equals(leavingPlayer.getUniqueId())) continue; - AnarchyExploitFixes.getDatastore().getJoinLeaveEnabled(onlinePlayer.getUniqueId()).thenAccept(enabled -> { + AnarchyExploitFixes.datastore().getJoinLeaveEnabled(onlinePlayer.getUniqueId()).thenAccept(enabled -> { if (enabled) { onlinePlayer.sendMessage(AnarchyExploitFixes.getLang(onlinePlayer.getLocale()).misc_leaveMessage .replace("%player%", leavingPlayer.getName())); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/MaskKickMessages.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/MaskKickMessages.java index 93262194e..8446e4777 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/MaskKickMessages.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/MaskKickMessages.java @@ -11,7 +11,7 @@ public class MaskKickMessages extends AEFModule implements Listener { public MaskKickMessages() { - super("misc.kicks.mask-kick-messages"); + super("misc.kicks.mask-kick-messages", false); config.addComment(configPath, "Configure mask message in lang folder."); } @@ -20,11 +20,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/PreventMessageKick.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/PreventMessageKick.java index 24aa41e3e..2b2ce91ad 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/PreventMessageKick.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/misc/PreventMessageKick.java @@ -17,7 +17,7 @@ public class PreventMessageKick extends AEFModule implements Listener { private final Set kickMessagesToListenTo; public PreventMessageKick() { - super("misc.kicks.prevent-message-kick"); + super("misc.kicks.prevent-message-kick", false); config.addComment(configPath + ".enable", "Cancels the kick for specific kick messages."); this.kickMessagesToListenTo = config.getList(configPath + ".kick-messages-to-listen-to", Arrays.asList("Kicked for spamming", "Stop spamming!")) @@ -31,11 +31,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/BeehiveCoordinates.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/BeehiveCoordinates.java index 2f8cfd8be..799955794 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/BeehiveCoordinates.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/BeehiveCoordinates.java @@ -16,8 +16,7 @@ public class BeehiveCoordinates extends PacketModule { private final String[] entityDataTagsToRemove; public BeehiveCoordinates() { - super("patches.remove-beehive-coordinates", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", + super("patches.remove-beehive-coordinates", true, PacketListenerPriority.HIGHEST, "Patches an exploit that allows players to obtain another player's\n" + "coordinates by trading them for Beehives or Beenests.\n" + "If the traded item contains any bees, the stored bee's NBT data can\n" + @@ -35,11 +34,6 @@ public BeehiveCoordinates() { .toArray(new String[0]); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void onPacketSend(PacketSendEvent event) { if (event.isCancelled()) return; @@ -58,7 +52,7 @@ public void onPacketSend(PacketSendEvent event) { } } - if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) { + else if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) { WrapperPlayServerWindowItems packet = new WrapperPlayServerWindowItems(event); for (int i = 0; i < packet.getItems().size(); i++) { diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/BigMessages.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/BigMessages.java new file mode 100755 index 000000000..0a6bd14a5 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/BigMessages.java @@ -0,0 +1,51 @@ +package me.xginko.aef.modules.packets; + +import com.github.retrooper.packetevents.event.PacketListenerPriority; +import com.github.retrooper.packetevents.event.PacketReceiveEvent; +import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; + +import java.nio.charset.StandardCharsets; + +public class BigMessages extends PacketModule { + + private final int charLimit; + private final boolean log, kick; + + public BigMessages() { + super("patches.message-char-limit", true, PacketListenerPriority.HIGHEST, + "Sets a character limit for command and message packets to prevent a lag exploit."); + this.charLimit = config.getInt(configPath + ".max-characters", 256); + this.log = config.getBoolean(configPath + ".log", false); + this.kick = config.getBoolean(configPath + ".kick-player", false); + } + + @Override + public void onPacketReceive(PacketReceiveEvent event) { + if (event.isCancelled()) return; + + if ( + event.getPacketType() == PacketType.Play.Client.CHAT_MESSAGE + || event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND + || event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND_UNSIGNED + ) { + if (isStringTooBig(event)) { + event.setCancelled(true); + onCancel(log, kick, event.getUser()); + } + } + } + + private boolean isStringTooBig(PacketReceiveEvent event) { + int strBufLen = ByteBufHelper.readVarInt(event.getByteBuf()); + + // Check if the received encoded string buffer length is zero or longer than maximum allowed + if (strBufLen < 0 || strBufLen > charLimit * 4) { + return true; + } + + // The received string length is longer than maximum allowed + return ByteBufHelper.toString(event.getByteBuf(), ByteBufHelper.readerIndex(event.getByteBuf()), strBufLen, StandardCharsets.UTF_8) + .length() > charLimit; + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/CraftingRecipeLag.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/CraftingRecipeLag.java index ef1e3c283..ac1cf58ce 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/CraftingRecipeLag.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/CraftingRecipeLag.java @@ -1,5 +1,6 @@ package me.xginko.aef.modules.packets; +import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.event.PacketListenerPriority; import com.github.retrooper.packetevents.event.PacketReceiveEvent; import com.github.retrooper.packetevents.protocol.packettype.PacketType; @@ -10,27 +11,37 @@ public class CraftingRecipeLag extends PacketModule { - private final ExpiringSet recipeCooldowns; + private final long cooldownMillis; private final boolean log, kick; + private ExpiringSet cooldowns; + public CraftingRecipeLag() { - super("patches.prevent-crafting-recipe-lag-exploit", PacketListenerPriority.HIGHEST); - shouldEnable(); - config.addComment(configPath + ".enable", + super("patches.prevent-crafting-recipe-lag-exploit", true, PacketListenerPriority.HIGHEST, "Prevent lag or crash caused by flooding the server with\n" + "crafting recipe book requests. This can even be done by hand on\n" + "servers with low specs. Only affects versions < 1.16"); - this.recipeCooldowns = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".crafting-recipe-delay-in-ticks", 5, + this.cooldownMillis = Math.max(1, config.getInt(configPath + ".crafting-recipe-delay-in-ticks", 5, "How many ticks a player needs to wait to be able to use\n" + - "the crafting recipe book again")) * 50L)); + "the crafting recipe book again")) * 50L; this.log = config.getBoolean(configPath + ".log", false); this.kick = config.getBoolean(configPath + ".kick-player", false); } @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); + public void enable() { + cooldowns = new ExpiringSet<>(Duration.ofMillis(cooldownMillis)); + PacketEvents.getAPI().getEventManager().registerListener(asAbstract); + } + + @Override + public void disable() { + PacketEvents.getAPI().getEventManager().unregisterListener(asAbstract); + if (cooldowns != null) { + cooldowns.clear(); + cooldowns.cleanUp(); + cooldowns = null; + } } @Override @@ -38,11 +49,11 @@ public void onPacketReceive(PacketReceiveEvent event) { if (event.isCancelled()) return; if (event.getPacketType() != PacketType.Play.Client.CRAFT_RECIPE_REQUEST) return; - if (recipeCooldowns.contains(event.getUser().getUUID())) { + if (cooldowns.contains(event.getUser().getUUID())) { event.setCancelled(true); onCancel(log, kick, event.getUser()); } else { - recipeCooldowns.add(event.getUser().getUUID()); + cooldowns.add(event.getUser().getUUID()); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/InventoryLag.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/InventoryLag.java index a25bc63b5..fcce29075 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/InventoryLag.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/InventoryLag.java @@ -34,46 +34,45 @@ public class InventoryLag extends PacketModule implements Listener { - private final Cache playerDataCache; private final Set measuredPacketTypes; - private final long rateLimitBytes, lockoutBytes, lockoutMillis; + private final long playerCacheMillis, rateLimitBytes, lockoutBytes, lockoutMillis; private final int screenOpenLimit, screenOpenDelay; private final boolean closeInventory, log; + private Cache playerDataCache; + public InventoryLag() { - super("patches.inventory-lag", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", + super("patches.inventory-lag", false, PacketListenerPriority.HIGHEST, "Checks if a player is requesting unusual amounts of traffic from the server\n" + - "using ItemStacks.\n" + - "If a player exceeds the limit, they will be put on a cooldown, during which\n" + - "they will be very limited in terms of ItemStack or Inventory interactions."); + "using ItemStacks.\n" + + "If a player exceeds the limit, they will be put on a cooldown, during which\n" + + "they will be very limited in terms of ItemStack or Inventory interactions."); this.log = config.getBoolean(configPath + ".log", false, "For debug purposes. Don't leave enabled for too long as it is very spammy."); this.closeInventory = config.getBoolean(configPath + ".close-open-inventory", true, "Whether to immediately close any open inventory of the player on limit exceed\n" + - "Note: Closing has to be scheduled so it will take a bit if the server is heavily\n" + - "lagging."); - this.playerDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(Math.max(1L, - config.getLong(configPath + ".byte-data-keep-time-millis", 30_000, - "The time in millis in which to check if the player exceeded the limit.\n" + - "Needs to be at least as long as your lockout duration millis.")))).build(); + "Note: Closing has to be scheduled so it will take a bit if the server is heavily\n" + + "lagging."); + this.playerCacheMillis = Math.max(1L, config.getLong(configPath + ".byte-data-keep-time-millis", 30_000, + "The time in millis in which to check if the player exceeded the limit.\n" + + "Needs to be at least as long as your lockout duration millis.")); this.rateLimitBytes = config.getLong(configPath + ".rate-limit.bytesize-limit", 8_000_000, "The limit in bytes the server has sent the server in the form of ItemStacks,\n" + - "before the player will be put on a rate-limit.\n" + - "Should always be lower than your lockout bytesize limit."); + "before the player will be put on a rate-limit.\n" + + "Should always be lower than your lockout bytesize limit."); this.screenOpenDelay = config.getInt(configPath + ".rate-limit.timeframe-millis", 2500, "The time in millis in which a player is allowed to open x amounts of windows\n" + - "but not more."); + "but not more."); this.screenOpenLimit = config.getInt(configPath + ".rate-limit.max-window-opens-per-timeframe", 2, "The amount of windows that can be opened during the timeframe-millis."); this.lockoutBytes = config.getLong(configPath + ".lockout.bytesize-limit", 24_000_000, "The upper limit in bytes a player is allowed to request from the server\n" + - "within the configured timeframe before he will be put on cooldown.\n" + - "During the cooldown, he will not be able to open any inventory screens\n" + - "or interact with items."); + "within the configured timeframe before he will be put on cooldown.\n" + + "During the cooldown, he will not be able to open any inventory screens\n" + + "or interact with items."); this.lockoutMillis = config.getLong(configPath + ".lockout.duration-millis", 15_000, "The time in milliseconds the player will have to wait before\n" + - "being able to open an inventory again after he exceeded the limit."); + "being able to open an inventory again after he exceeded the limit."); this.measuredPacketTypes = config.getList(configPath + ".check-packets", Arrays.asList("SET_SLOT", "WINDOW_ITEMS")) .stream() .map(configuredPacketType -> { @@ -88,13 +87,9 @@ public InventoryLag() { .collect(Collectors.toCollection(HashSet::new)); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void enable() { + playerDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(playerCacheMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); PacketEvents.getAPI().getEventManager().registerListener(asAbstract); } @@ -103,6 +98,11 @@ public void enable() { public void disable() { HandlerList.unregisterAll(this); PacketEvents.getAPI().getEventManager().unregisterListener(asAbstract); + if (playerDataCache != null) { + playerDataCache.invalidateAll(); + playerDataCache.cleanUp(); + playerDataCache = null; + } } @Override diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/LecternCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/LecternCrash.java index 5cc6d6b00..a5d317ec2 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/LecternCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/LecternCrash.java @@ -13,18 +13,17 @@ public class LecternCrash extends PacketModule { private final boolean log, kick; public LecternCrash() { - super("patches.lectern-crash-patch", PacketListenerPriority.HIGHEST); - try { this.LECTERN = InventoryType.valueOf("LECTERN"); } catch (IllegalArgumentException ignored) {} - config.addComment(configPath + ".enable", + super("patches.lectern-crash-patch", false, PacketListenerPriority.HIGHEST, "Patches an instant server crash exploit that involves sending\n" + "an invalid Window Click packet while taking a book out of a Lectern."); + try { this.LECTERN = InventoryType.valueOf("LECTERN"); } catch (IllegalArgumentException ignored) {} this.log = config.getBoolean(configPath + ".log", false); this.kick = config.getBoolean(configPath + ".kick-player", false); } @Override public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true) && LECTERN != null; + return configEnabled && LECTERN != null; } @Override diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/MapCursorLag.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/MapCursorLag.java index 9be90524c..59533a1e1 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/MapCursorLag.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/MapCursorLag.java @@ -19,24 +19,18 @@ public class MapCursorLag extends PacketModule implements Listener { public MapCursorLag() { - super("patches.map-cursor-lag-patch", PacketListenerPriority.HIGHEST); - config.addComment( configPath + ".enable", + super("patches.map-cursor-lag-patch", true, PacketListenerPriority.HIGHEST, "Patches the famous stacked map cursor lag that causes both \n" + "client and server crashes."); } @Override public void enable() { - if (EntityUtil.canDisableMapPositionCursor()) + if (EntityUtil.MAP_SET_TRACKING_POS_AVAILABLE) plugin.getServer().getPluginManager().registerEvents(this, plugin); PacketEvents.getAPI().getEventManager().registerListener(asAbstract); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -68,9 +62,8 @@ private void onChunkLoad(ChunkLoadEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onInteract(PlayerInteractEntityEvent event) { - Entity rightClicked = event.getRightClicked(); - if (EntityUtil.ITEM_FRAMES.contains(rightClicked.getType())) { - EntityUtil.disableMapPositionCursor((ItemFrame) rightClicked); + if (EntityUtil.ITEM_FRAMES.contains(event.getRightClicked().getType())) { + EntityUtil.disableMapPositionCursor((ItemFrame) event.getRightClicked()); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/NoComExploit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/NoComExploit.java index 6ec63286c..9c96e4fcb 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/NoComExploit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/NoComExploit.java @@ -20,9 +20,7 @@ public class NoComExploit extends PacketModule { private final boolean log, kick; public NoComExploit() { - super("patches.prevent-nocom-coordinate-exploit", PacketListenerPriority.HIGHEST); - shouldEnable(); - config.addComment(configPath + ".enable", + super("patches.prevent-nocom-coordinate-exploit", true, PacketListenerPriority.HIGHEST, "Prevents the abusable mechanic used by the infamous \"No Comment\"\n" + "coordinate exploit, where the server responds to requests that are\n" + "far outside of the sending player's reach, therefore either crashing\n" + @@ -35,11 +33,6 @@ public NoComExploit() { this.kick = config.getBoolean(configPath + ".kick-player", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void onPacketReceive(PacketReceiveEvent event) { if (event.isCancelled()) return; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/PacketModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/PacketModule.java index cf4275353..d9cf7d734 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/PacketModule.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/PacketModule.java @@ -9,16 +9,19 @@ import me.xginko.aef.utils.models.ExpiringSet; import java.time.Duration; -import java.util.Set; import java.util.UUID; public abstract class PacketModule extends AEFModule implements PacketListener { protected final PacketListenerAbstract asAbstract; - private final Set loggingCooldown; + protected final ExpiringSet loggingCooldown; - public PacketModule(String configPath, PacketListenerPriority priority) { - super(configPath); + public PacketModule(String configPath, boolean enabledByDefault, PacketListenerPriority priority) { + this(configPath, enabledByDefault, priority, null); + } + + public PacketModule(String configPath, boolean enabledByDefault, PacketListenerPriority priority, String comment) { + super(configPath, enabledByDefault, comment); this.asAbstract = asAbstract(priority); // Otherwise will log for each received packet, which would be a LOT this.loggingCooldown = new ExpiringSet<>(Duration.ofMinutes(5)); @@ -35,11 +38,9 @@ public void disable() { } public void onCancel(boolean log, boolean kick, User sender) { - if (log) { - if (!loggingCooldown.contains(sender.getUUID())) { - info(sender.getName() + " failed to trigger exploit."); - loggingCooldown.add(sender.getUUID()); - } + if (log && !loggingCooldown.contains(sender.getUUID())) { + info(sender.getName() + " failed to trigger exploit."); + loggingCooldown.add(sender.getUUID()); } if (kick) { diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/PurpurBeehiveCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/PurpurBeehiveCrash.java index bb1394e88..22f97b3d1 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/PurpurBeehiveCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/PurpurBeehiveCrash.java @@ -23,7 +23,7 @@ public class PurpurBeehiveCrash extends PacketModule { private final boolean log, kick; public PurpurBeehiveCrash() { - super("patches.beehive-crash-patch", PacketListenerPriority.HIGHEST); + super("patches.beehive-crash-patch", PlatformUtil.isPurpur(), PacketListenerPriority.HIGHEST); config.addComment(configPath + ".enable", "Patches a server crash exploit exclusive to Purpur servers.\n" + "This exploit works due to PurpurClient having a feature that\n" + @@ -38,11 +38,6 @@ public PurpurBeehiveCrash() { this.kick = config.getBoolean(configPath + ".kick-player", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", PlatformUtil.isPurpur()); - } - @Override @SuppressWarnings("UnstableApiUsage") public void onPacketReceive(PacketReceiveEvent event) { diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/SequenceCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/SequenceCrash.java index 0a4556b97..d5251f28f 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/SequenceCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/SequenceCrash.java @@ -13,8 +13,7 @@ public class SequenceCrash extends PacketModule { private final boolean log, kick; public SequenceCrash() { - super("patches.sequence-crash-patch", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", + super("patches.sequence-crash-patch", PlatformUtil.getMinecraftVersion() >= 19, PacketListenerPriority.HIGHEST, "Patches a variety of lag/crash exploits that involves sending packets \n" + "with invalid sequences."); this.log = config.getBoolean(configPath + ".log", false); @@ -23,7 +22,7 @@ public SequenceCrash() { @Override public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true) && PlatformUtil.getMinecraftVersion() >= 19; + return configEnabled && PlatformUtil.getMinecraftVersion() >= 19; } @Override diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/SignLag.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/SignLag.java index 33050debe..8a4d9b4bb 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/SignLag.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/SignLag.java @@ -1,5 +1,6 @@ package me.xginko.aef.modules.packets; +import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.event.PacketListenerPriority; import com.github.retrooper.packetevents.event.PacketReceiveEvent; import com.github.retrooper.packetevents.protocol.packettype.PacketType; @@ -11,19 +12,19 @@ public class SignLag extends PacketModule { - private final ExpiringSet cooldowns; + private final long cooldownMillis; private final int line_char_limit, total_char_limit; private final boolean log, kick; + private ExpiringSet cooldowns; + public SignLag() { - super("patches.sign-lag", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", + super("patches.sign-lag", true, PacketListenerPriority.HIGHEST, "Patches a lag exploit that involves sending specific oversized \n" + "sign edit packets."); - this.cooldowns = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".packet-delay-in-ticks", 10, - "How many ticks a player needs to wait to be able to send\n" + - "another sign update packet (renaming or writing).")) * 50L)); + this.cooldownMillis = Math.max(1, config.getInt(configPath + ".packet-delay-in-ticks", 10, + "How many ticks a player needs to wait to be able to send\n" + + "another sign update packet (renaming or writing).")) * 50L; this.line_char_limit = config.getInt(configPath + ".line-character-limit", 80, "Vanilla limit is 384 characters per line, which is too much."); this.total_char_limit = config.getInt(configPath + ".total-char-limit", 384, @@ -33,8 +34,19 @@ public SignLag() { } @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); + public void enable() { + cooldowns = new ExpiringSet<>(Duration.ofMillis(cooldownMillis)); + PacketEvents.getAPI().getEventManager().registerListener(asAbstract); + } + + @Override + public void disable() { + PacketEvents.getAPI().getEventManager().unregisterListener(asAbstract); + if (cooldowns != null) { + cooldowns.clear(); + cooldowns.cleanUp(); + cooldowns = null; + } } @Override @@ -42,8 +54,12 @@ public void onPacketReceive(PacketReceiveEvent event) { if (event.isCancelled()) return; if (event.getPacketType() != PacketType.Play.Client.UPDATE_SIGN) return; - if (cooldowns.contains(event.getUser().getUUID())) return; - cooldowns.add(event.getUser().getUUID()); + if (cooldowns.contains(event.getUser().getUUID())) { + event.setCancelled(true); + return; + } else { + cooldowns.add(event.getUser().getUUID()); + } int sum = 0; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/TabCompleteCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/TabCompleteCrash.java index e6227dd26..73a045a97 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/TabCompleteCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/TabCompleteCrash.java @@ -6,24 +6,21 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientTabComplete; import org.bukkit.permissions.ServerOperator; +import java.util.Arrays; + public class TabCompleteCrash extends PacketModule { - private static final String[] ABUSABLE_SEQUENCES = { "@", "[", "nbt", "=", "{", "}", "]" }; + private final String[] sequences; private final boolean log, kick; public TabCompleteCrash() { - super("patches.tab-complete-crash-patch", PacketListenerPriority.HIGHEST); - config.addComment(configPath + ".enable", + super("patches.tab-complete-crash-patch", true, PacketListenerPriority.HIGHEST, "Patches two lag exploits and an instant server shutdown exploit that\n" + "works by sending a malicious TabComplete packet that triggers a\n" + "StackOverflowError inside the TagParser class."); this.log = config.getBoolean(configPath + ".log", false); this.kick = config.getBoolean(configPath + ".kick-player", false); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); + this.sequences = config.getList(configPath + ".characters", Arrays.asList("@", "[", "nbt", "=", "{", "}", "]")).toArray(new String[0]); } @Override @@ -51,8 +48,8 @@ public void onPacketReceive(PacketReceiveEvent event) { if (event.getPlayer() == null || ((ServerOperator) event.getPlayer()).isOp()) return; - for (String sequence : ABUSABLE_SEQUENCES) { - if (text.indexOf(sequence) != -1) { + for (String sequence : sequences) { + if (text.contains(sequence)) { event.setCancelled(true); onCancel(log, kick, event.getUser()); return; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/WindowClickCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/WindowClickCrash.java index 90b2429b2..80bd48340 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/WindowClickCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/packets/WindowClickCrash.java @@ -11,7 +11,7 @@ public class WindowClickCrash extends PacketModule { private final boolean log, kick; public WindowClickCrash() { - super("patches.window-click-crash-patch", PacketListenerPriority.HIGHEST); + super("patches.window-click-crash-patch", true, PacketListenerPriority.HIGHEST); config.addComment(configPath + ".enable", "Patches a variety of different lag and crash methods that work\n" + "by sending invalid Window Click packets, causing the server to\n" + @@ -20,15 +20,11 @@ public WindowClickCrash() { this.kick = config.getBoolean(configPath + ".kick-player", false); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void onPacketReceive(PacketReceiveEvent event) { if (event.isCancelled()) return; if (event.getPacketType() != PacketType.Play.Client.CLICK_WINDOW) return; + WrapperPlayClientClickWindow packet = new WrapperPlayClientClickWindow(event); int button = packet.getButton(); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/GodMode.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/GodMode.java index 6984ada84..9b6cbc9b1 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/GodMode.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/GodMode.java @@ -15,8 +15,7 @@ public class GodMode extends AEFModule implements Listener { public GodMode() { - super("patches.experimental-godmode-patch"); - config.addComment(configPath, + super("patches.experimental-godmode-patch", false, "Removes entities or players if they are invalid, dead or not located\n" + "within a ticking chunk. Not sure if this works."); } @@ -26,11 +25,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/BookBan.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/ItemDataBan.java similarity index 78% rename from AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/BookBan.java rename to AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/ItemDataBan.java index 708efe73d..a6f07c9be 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/BookBan.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/ItemDataBan.java @@ -23,14 +23,19 @@ import java.time.Duration; import java.util.UUID; -public class BookBan extends AEFModule implements Listener { +public class ItemDataBan extends AEFModule implements Listener { - private final Cache cachedItemSizes, cachedInventorySizes; + private final long itemSizeCacheMillis, inventorySizeCacheMillis; private final int maxBookSize, maxItemSize, maxInventorySize, maxAuthorChars, maxTitleChars, maxPages; private final boolean useUTF16, kickOnBigBook; - public BookBan() { - super("patches.anti-book-ban"); + private Cache cachedItemSizes, cachedInventorySizes; + + public ItemDataBan() { + super("patches.anti-item-ban", false, + "More commonly known as book-ban: \n" + + "Prevents player's getting banned from items with big nbt/compound data. \n" + + "This check applies to all item data, not just books."); this.useUTF16 = config.getBoolean(configPath + ".use-UTF-16", false, "If set to false, will use UTF-8. \n" + "Charset to use to encode the result of NBTCompound#toString into \n" + @@ -40,38 +45,39 @@ public BookBan() { this.maxBookSize = config.getInt(configPath + ".max-book-size", 56000); this.kickOnBigBook = config.getBoolean(configPath + ".kick-on-too-large-book-edit", true, "Kicks players when they try to create a book bigger than the limit."); - this.maxAuthorChars = config.getInt(configPath + ".max-author-chars", 32); - this.maxTitleChars = config.getInt(configPath + ".max-title-chars", 32); + this.maxAuthorChars = config.getInt(configPath + ".max-author-chars", 30); + this.maxTitleChars = config.getInt(configPath + ".max-title-chars", 30); this.maxPages = config.getInt(configPath + ".max-pages", 100); this.maxItemSize = config.getInt(configPath + ".max-item-size", 56000); this.maxInventorySize = config.getInt(configPath + ".max-inventory-size", 2050000); - this.cachedItemSizes = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis( - Math.max(1, config.getInt(configPath + ".dropped-items-size-cache-ticks", 120, - "How long in ticks a dropped item's size should be cached after\n" + - "checking.")) * 50L - )).build(); - this.cachedInventorySizes = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis( - Math.max(1, config.getInt(configPath + ".player-inventory-size-cache-ticks", 20, - "How long in ticks a player's inventory size should be cached after\n" + - "checking.")) * 50L - )).build(); + this.itemSizeCacheMillis = Math.max(1,config.getInt(configPath + ".dropped-items-size-cache-ticks", 120, + "How long in ticks a dropped item's size should be cached after\n" + + "checking.")) * 50L; + this.inventorySizeCacheMillis = Math.max(1, config.getInt(configPath + ".player-inventory-size-cache-ticks", 20, + "How long in ticks a player's inventory size should be cached after\n" + + "checking.")) * 50L; } @Override public void enable() { + cachedItemSizes = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(itemSizeCacheMillis)).build(); + cachedInventorySizes = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(inventorySizeCacheMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); - cachedInventorySizes.cleanUp(); - cachedItemSizes.cleanUp(); + if (cachedItemSizes != null) { + cachedItemSizes.invalidateAll(); + cachedItemSizes.cleanUp(); + cachedItemSizes = null; + } + if (cachedInventorySizes != null) { + cachedInventorySizes.invalidateAll(); + cachedInventorySizes.cleanUp(); + cachedInventorySizes = null; + } } // Prevent players from creating big books diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/PearlPhase.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/PearlPhase.java deleted file mode 100644 index 18f0d9372..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/PearlPhase.java +++ /dev/null @@ -1,109 +0,0 @@ -package me.xginko.aef.modules.patches; - -import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.LocationUtil; -import me.xginko.aef.utils.MaterialUtil; -import me.xginko.aef.utils.WorldUtil; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerTeleportEvent; - -import java.util.EnumSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class PearlPhase extends AEFModule implements Listener { - - private final Set glitchyMaterial; - private final double maxDistance; - private final int radius; - - public PearlPhase() { - super("patches.pearl-phase"); - config.addComment(configPath+ ".enable", - "Attempts to patch a pearl phasing exploit by cancelling the teleport\n" + - "if the pearl is thrown at or near a specific block.\n" + - "At the time of the creation of this module, this is an issue with NoCheatPlus."); - this.radius = Math.min(1, config.getInt(configPath + ".search-radius", 2, - "How many blocks around the teleport location should be searched\n" + - "for potential glitch blocks if the teleport location isn't one itself.")); - this.maxDistance = config.getDouble(configPath + ".maximum-distance-to-cancel-teleport", 3.0); - Stream concatA = Stream.concat(MaterialUtil.SLAB_LIKE.stream(), - Stream.of(XMaterial.COBWEB, XMaterial.POWDER_SNOW).filter(XMaterial::isSupported).map(XMaterial::parseMaterial)); - Stream concatB = Stream.concat(MaterialUtil.PRESSURE_PLATES.stream(), MaterialUtil.TRAPDOORS.stream()); - List defaults = Stream.concat(concatA, concatB) - .map(Enum::name) - .sorted() - .collect(Collectors.toList()); - this.glitchyMaterial = config.getList(configPath+".glitchy-materials", defaults) - .stream() - .map(configuredType -> { - try { - return Material.valueOf(configuredType); - } catch (IllegalArgumentException e) { - notRecognized(Material.class, configuredType); - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath+".enable", false); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPlayerTeleport(PlayerTeleportEvent event) { - if (event.getCause() != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) return; - - Location destination = event.getTo(); - if (LocationUtil.getRelDistance2D(event.getFrom(), destination) >= maxDistance) return; - - Block destBlock = destination.getBlock(); - - if (glitchyMaterial.contains(destBlock.getType())) { - event.setCancelled(true); - return; - } - - int centerX = destBlock.getX(); - int centerY = destBlock.getY(); - int centerZ = destBlock.getZ(); - World world = destBlock.getWorld(); - - for (int x = centerX - radius; x <= centerX + radius; x++) { - for (int z = centerZ - radius; z <= centerZ + radius; z++) { - for (int y = Math.max(WorldUtil.getMinWorldHeight(world), centerY - radius); y <= centerY + radius; y++) { - if (y > world.getMaxHeight()) break; - - if (glitchyMaterial.contains(world.getBlockAt(x, y, z).getType())) { - event.setCancelled(true); - return; - } - } - } - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/TeleportCoordExploit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/TeleportCoordExploit.java index 17aaa72c1..4ec427216 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/TeleportCoordExploit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/TeleportCoordExploit.java @@ -16,11 +16,10 @@ public class TeleportCoordExploit extends AEFModule implements Listener { private final int minDistanceToVanishPlayers; public TeleportCoordExploit() { - super("patches.prevent-teleport-coordinate-exploit"); - config.addComment(configPath + ".enable", + super("patches.prevent-teleport-coordinate-exploit", true, "Patches coordinate exploit for teleportation commands such as /tpa,\n" + - "/home AS WELL as respawn exploits. \n" + - "This is done by vanishing the player for x ticks before teleporting."); + "/home AS WELL as respawn exploits. \n" + + "This is done by vanishing the player for x ticks before teleporting."); this.minDistanceToVanishPlayers = config.getInt(configPath + ".min-distance-to-vanish-player", 100); this.teleportVanishTime = config.getInt(configPath + ".teleport-vanish-time-in-ticks", 10); } @@ -30,11 +29,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -62,6 +56,8 @@ private void onTeleport(PlayerTeleportEvent event) { case PLUGIN: case COMMAND: case ENDER_PEARL: + case UNKNOWN: + case SPECTATE: if (LocationUtil.getRelDistance2D(event.getFrom(), event.getTo()) >= minDistanceToVanishPlayers) { Player player = event.getPlayer(); vanish(player); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/commandsign/CommandSign.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/commandsign/CommandSign.java index 8868c5bb7..be715966f 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/commandsign/CommandSign.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/commandsign/CommandSign.java @@ -1,9 +1,9 @@ package me.xginko.aef.modules.patches.commandsign; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; @@ -16,11 +16,10 @@ public class CommandSign extends AEFModule implements Listener { private final Listener signCommandListener; public CommandSign() { - super("patches.prevent-command-sign"); - config.addComment(configPath + ".enable", + super("patches.prevent-command-sign", true, "Patch signs that have run_command NBT tags attached, allowing the \n" + - "to run a command with operator permissions on click. \n" + - "Recommended to enable if you had a rogue admin or backdoor incident."); + "to run a command with operator permissions on click. \n" + + "Recommended to enable if you had a rogue admin or backdoor incident."); this.signCommandListener = SignCommandListener.isSupported() ? new SignCommandListener() : this; } @@ -29,11 +28,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(signCommandListener, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(signCommandListener); @@ -45,7 +39,7 @@ private void onInteract(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; if (!MaterialUtil.SIGNS.contains(event.getClickedBlock().getType())) return; - if (!CachingPermTool.hasPermission(AEFPermission.BYPASS_PREVENTION_COMMANDSIGN, event.getPlayer())) { + if (!AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), AEFPermission.BYPASS_PREVENTION_COMMANDSIGN.node()).toBoolean()) { event.setCancelled(true); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/DispenserCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/DispenserCrash.java index 8cd71dd43..1102dadef 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/DispenserCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/DispenserCrash.java @@ -15,10 +15,9 @@ public class DispenserCrash extends AEFModule implements Listener { private final boolean logIsEnabled; public DispenserCrash() { - super("patches.prevent-dispenser-crash"); - config.addComment(configPath + ".enable", + super("patches.prevent-dispenser-crash", true, "Prevents dispensers from crashing the server when dispensing\n" + - "items out of bounds: https://www.youtube.com/watch?v=XL17P87O6xA"); + "items out of bounds: https://www.youtube.com/watch?v=XL17P87O6xA"); this.logIsEnabled = config.getBoolean(configPath + ".log", false); } @@ -27,11 +26,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/EndGatewayCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/EndGatewayCrash.java index 4067f7265..bfa7062c2 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/EndGatewayCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/EndGatewayCrash.java @@ -14,8 +14,7 @@ public class EndGatewayCrash extends AEFModule implements Listener { private final boolean logIsEnabled; public EndGatewayCrash() { - super("patches.prevent-end-gateway-crash"); - config.addComment(configPath + ".enable", + super("patches.prevent-end-gateway-crash", true, "Prevents a crash exploit involving boats and end gateways:\n" + "https://www.youtube.com/watch?v=c5nVBQeYo-I"); this.logIsEnabled = config.getBoolean(configPath + ".log", true); @@ -26,11 +25,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/MultipleEnderdragons.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/MultipleEnderdragons.java index 2de326e8d..8e64207a4 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/MultipleEnderdragons.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/MultipleEnderdragons.java @@ -14,7 +14,7 @@ public class MultipleEnderdragons extends AEFModule implements Listener { private final boolean logIsEnabled; public MultipleEnderdragons() { - super("patches.prevent-multiple-enderdragons"); + super("patches.prevent-multiple-enderdragons", false); this.logIsEnabled = config.getBoolean(configPath + ".log", true); } @@ -23,11 +23,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/RedstoneOnTrapdoorCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/RedstoneOnTrapdoorCrash.java index 694918fdf..d80702492 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/RedstoneOnTrapdoorCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/RedstoneOnTrapdoorCrash.java @@ -1,13 +1,12 @@ package me.xginko.aef.modules.patches.crashexploits; +import com.cryptomorin.xseries.XMaterial; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.MaterialUtil; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -17,65 +16,59 @@ import org.bukkit.event.block.BlockRedstoneEvent; import java.time.Duration; +import java.util.concurrent.atomic.AtomicInteger; public class RedstoneOnTrapdoorCrash extends AEFModule implements Listener { - private final Cache trapdoorActivationCache; + private final long cacheTimeMillis; private final int trapdoorActivationLimit; private final boolean logIsEnabled; + private Cache trapdoorActivationCache; + public RedstoneOnTrapdoorCrash() { - super("patches.prevent-redstone-on-trapdoor-crash"); - config.addComment(configPath + ".enable", + super("patches.prevent-redstone-on-trapdoor-crash", true, "prevents a powerful crash exploit present in 1.13 - 1.19.3"); this.logIsEnabled = config.getBoolean(configPath + ".log", true); this.trapdoorActivationLimit = config.getInt(configPath + ".max-trapdoor-activations-by-redstone-per-time", 10); - this.trapdoorActivationCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis( - Math.max(config.getInt(configPath + ".time-in-ticks", 30, "1 sec = 20 ticks"), 1) * 50L - )).build(); + this.cacheTimeMillis = Math.max(1, config.getInt(configPath + ".time-in-ticks", 30, "1 sec = 20 ticks")) * 50L; } @Override public void enable() { + trapdoorActivationCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cacheTimeMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (trapdoorActivationCache != null) { + trapdoorActivationCache.invalidateAll(); + trapdoorActivationCache.cleanUp(); + trapdoorActivationCache = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onRedstonePowerTrapdoor(BlockRedstoneEvent event) { - Block block = event.getBlock(); - if (!MaterialUtil.TRAPDOORS.contains(block.getType())) return; - - final Location trapdoorLoc = block.getLocation(); - Integer activationCount = trapdoorActivationCache.getIfPresent(trapdoorLoc); - if (activationCount == null) activationCount = 0; + if (!MaterialUtil.TRAPDOORS.contains(event.getBlock().getType())) return; - activationCount++; - trapdoorActivationCache.put(trapdoorLoc, activationCount); + final Location trapdoorLoc = event.getBlock().getLocation(); - if (activationCount > trapdoorActivationLimit) { - block.setType(Material.AIR); + if (trapdoorActivationCache.get(trapdoorLoc, k -> new AtomicInteger()).incrementAndGet() > trapdoorActivationLimit) { + event.getBlock().setType(XMaterial.AIR.get()); if (logIsEnabled) info("Prevented potential trapdoor crash at " + LocationUtil.toString(trapdoorLoc)); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPlace(BlockPlaceEvent event) { - Block block = event.getBlock(); - if (block == null || !MaterialUtil.REDSTONE.contains(block.getType())) return; + if (event.getBlock() == null || !MaterialUtil.REDSTONE.contains(event.getBlock().getType())) return; - if (MaterialUtil.TRAPDOORS.contains(block.getRelative(BlockFace.DOWN).getType())) { + if (MaterialUtil.TRAPDOORS.contains(event.getBlock().getRelative(BlockFace.DOWN).getType())) { event.setCancelled(true); - if (logIsEnabled) info("Prevented potential trapdoor crash at " + LocationUtil.toString(block.getLocation())); + if (logIsEnabled) info("Prevented potential trapdoor crash at " + LocationUtil.toString(event.getBlock().getLocation())); } } } \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/WorldChangeCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/WorldChangeCrash.java index 7fddd8b8a..5a601c3ad 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/WorldChangeCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/patches/crashexploits/WorldChangeCrash.java @@ -14,34 +14,35 @@ public class WorldChangeCrash extends AEFModule implements Listener { - private final ExpiringSet recentWorldChangers; + private final long worldChangeDelayMillis; private final boolean logIsEnabled; + private ExpiringSet recentWorldChangers; + public WorldChangeCrash() { - super("patches.prevent-fast-world-teleport-crash"); - this.recentWorldChangers = new ExpiringSet<>(Duration.ofMillis( - Math.max(config.getInt(configPath + ".teleport-delay-millis", 1000, - "Time in milliseconds until an entity can teleport to\n" + - "another world again."), 1))); - config.addComment(configPath + ".enable", + super("patches.prevent-fast-world-teleport-crash", true, "Prevents crash methods that involve very fast teleporting\n" + - "between different worlds in a short time."); + "between different worlds in a short time."); + this.worldChangeDelayMillis = Math.max(1, config.getInt(configPath + ".teleport-delay-millis", 1000, + "Time in milliseconds until an entity can teleport to\n" + + "another world again.")); this.logIsEnabled = config.getBoolean(configPath + ".log", false); } @Override public void enable() { + recentWorldChangers = new ExpiringSet<>(Duration.ofMillis(worldChangeDelayMillis)); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (recentWorldChangers != null) { + recentWorldChangers.clear(); + recentWorldChangers.cleanUp(); + recentWorldChangers = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/BedTrap.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/BedTrap.java index 515a83b71..edfc7899e 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/BedTrap.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/BedTrap.java @@ -14,59 +14,53 @@ import java.time.Duration; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; public class BedTrap extends AEFModule implements Listener { - private final Cache playerDeathNearBedCount; + private final long timeInSeconds; private final double maxBedDistanceSquared; private final int maxDeathsPerTime; private final boolean logIsEnabled; + private Cache playerDeathNearBedCount; + public BedTrap() { - super("preventions.anti-bed-trap"); - config.addComment(configPath + ".enable", - "Resets a players bed respawn they die too many times within \n" + + super("preventions.anti-bed-trap", false, + "Resets a players bed respawn they die too many times within\n" + "a certain timeframe."); this.logIsEnabled = config.getBoolean(configPath + ".log", false); this.maxDeathsPerTime = config.getInt(configPath + ".max-deaths-per-time", 7, "Amount of times player can die until he is determined as bed-trapped."); - this.playerDeathNearBedCount = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds( - Math.max(1, config.getInt(configPath + ".time-in-seconds", 5, - "Time until death counter will be reset again")))).build(); + this.timeInSeconds = Math.max(1, config.getInt(configPath + ".time-in-seconds", 5, + "Time until death counter will be reset again")); this.maxBedDistanceSquared = NumberConversions.square(config.getDouble(configPath + ".max-distance-from-bed", 6.0)); } @Override public void enable() { + playerDeathNearBedCount = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(timeInSeconds)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (playerDeathNearBedCount != null) { + playerDeathNearBedCount.invalidateAll(); + playerDeathNearBedCount.cleanUp(); + playerDeathNearBedCount = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onDeath(PlayerDeathEvent event) { - final Player player = event.getEntity(); - if (!isNearBedSpawn(player)) return; - - Integer nearBedDeaths = playerDeathNearBedCount.getIfPresent(player.getUniqueId()); - if (nearBedDeaths == null) nearBedDeaths = 0; - nearBedDeaths++; + if (!isNearBedSpawn(event.getEntity())) return; - if (nearBedDeaths > maxDeathsPerTime) { - player.setBedSpawnLocation(null, true); - if (logIsEnabled) info("Reset bed respawn of potentially bed-trapped player '" + player.getName() + "'"); - return; + if (playerDeathNearBedCount.get(event.getEntity().getUniqueId(), k -> new AtomicInteger()).incrementAndGet() > maxDeathsPerTime) { + event.getEntity().setBedSpawnLocation(null, true); + if (logIsEnabled) info("Reset bed respawn of potentially bed-trapped player '" + event.getEntity().getName() + "'"); } - - playerDeathNearBedCount.put(player.getUniqueId(), nearBedDeaths); } private boolean isNearBedSpawn(Player player) { diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/DisableFish.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/DisableFish.java deleted file mode 100755 index 211b75c91..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/DisableFish.java +++ /dev/null @@ -1,63 +0,0 @@ -package me.xginko.aef.modules.preventions; - -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.PlatformUtil; -import org.bukkit.entity.EntityType; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.util.Arrays; -import java.util.EnumSet; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -public class DisableFish extends AEFModule implements Listener { - - private final Set disabledFishes; - - public DisableFish() { - super("preventions.prevent-ambient-fish-spawns"); - config.addComment(configPath + ".enable", - "Prevent certain fish types from spawning in newer versions to combat lag."); - this.disabledFishes = config.getList(configPath + ".fish-types-to-prevent", - Arrays.asList("COD", "SALMON", "PUFFERFISH", "TROPICAL_FISH")) - .stream() - .map(configuredFish -> { - try { - return EntityType.valueOf(configuredFish); - } catch (IllegalArgumentException exception) { - if (PlatformUtil.getMinecraftVersion() > 12) - notRecognized(EntityType.class, configuredFish); - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityType.class))); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false) && PlatformUtil.getMinecraftVersion() > 12; - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onCreatureSpawn(CreatureSpawnEvent event) { - if (disabledFishes.contains(event.getEntity().getType())) { - event.setCancelled(true); - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/IllegalGameMode.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/IllegalGameMode.java new file mode 100755 index 000000000..fb2f29296 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/IllegalGameMode.java @@ -0,0 +1,122 @@ +package me.xginko.aef.modules.preventions; + +import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.modules.AEFModule; +import org.bukkit.GameMode; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class IllegalGameMode extends AEFModule implements Listener { + + private final Map worldSettings; + private final Set allowedGamemodePlayers; + private final GameMode defaultGamemode; + private final boolean shouldLog; + + public IllegalGameMode() { + super("preventions.illegal-gamemode", false, + "Forces GameMode for players not in the whitelist.\n" + + "Useful protection against past and future backdoor incidents."); + this.shouldLog = config.getBoolean(configPath + ".log", true); + + GameMode gameMode; + String configuredGamemode = config.getString(configPath + ".default-gamemode", GameMode.SURVIVAL.name(), + "GameModes: " + Arrays.stream(GameMode.values()).map(Enum::name).collect(Collectors.joining(", "))); + try { + gameMode = GameMode.valueOf(configuredGamemode); + } catch (IllegalArgumentException e) { + notRecognized(GameMode.class, configuredGamemode); + gameMode = GameMode.SURVIVAL; + } + this.defaultGamemode = gameMode; + + Map defaults = new HashMap<>(3); + defaults.put("world", GameMode.SURVIVAL.name()); + defaults.put("world_nether", GameMode.SURVIVAL.name()); + defaults.put("world_the_end", GameMode.SURVIVAL.name()); + + ConfigSection section = config.getConfigSection(configPath + ".world-gamemodes", defaults); + List worlds = section.getKeys(false); + this.worldSettings = new HashMap<>(worlds.size()); + for (String world : worlds) { + try { + worldSettings.put(world, GameMode.valueOf(section.getString(world))); + } catch (IllegalArgumentException e) { + notRecognized(GameMode.class, world); + } + } + + this.allowedGamemodePlayers = new HashSet<>(config.getList(configPath + ".whitelisted-players", + Collections.singletonList("Notch"))); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + private void checkForIllegalGameMode(HumanEntity player) { + if (allowedGamemodePlayers.contains(player.getName())) return; + + GameMode targetGamemode = worldSettings.getOrDefault(player.getWorld().getName(), defaultGamemode); + + if (player.getGameMode() != targetGamemode) { + if (shouldLog) warn(player.getName() + " is GameMode " + player.getGameMode().name() + + " in world " + player.getWorld().getName() + ". Setting to " + targetGamemode.name()); + player.setGameMode(targetGamemode); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onInventory(InventoryEvent event) { + checkForIllegalGameMode(event.getView().getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onJoin(PlayerJoinEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onLeave(PlayerQuitEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onMove(PlayerMoveEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST) + private void onChat(AsyncPlayerChatEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST) + private void onCommand(PlayerCommandPreprocessEvent event) { + checkForIllegalGameMode(event.getPlayer()); + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/PreventOppedPlayers.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/IllegalPermissions.java similarity index 57% rename from AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/PreventOppedPlayers.java rename to AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/IllegalPermissions.java index 4728d6a05..ec88b9afc 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/PreventOppedPlayers.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/IllegalPermissions.java @@ -1,6 +1,8 @@ package me.xginko.aef.modules.preventions; +import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.enums.TriState; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -16,16 +18,18 @@ import java.util.HashSet; import java.util.Set; -public class PreventOppedPlayers extends AEFModule implements Listener { +public class IllegalPermissions extends AEFModule implements Listener { - private final Set allowedOperators; - private final boolean logIsEnabled; + private final Set allowedOperators, blacklistedPermissions; + private final boolean shouldLog; - public PreventOppedPlayers() { - super("preventions.prevent-opped-players"); - config.addComment(configPath + ".enable", "Useful if you suspect a backdoor has happened."); - this.logIsEnabled = config.getBoolean(configPath + ".log", true); + public IllegalPermissions() { + super("preventions.illegal-permissions", false, + "Strips/prevents certain permissions being used by unauthorized players.\n" + + "Useful protection against past and future backdoor incidents"); + this.shouldLog = config.getBoolean(configPath + ".log", true); this.allowedOperators = new HashSet<>(config.getList(configPath + ".whitelisted-players", Collections.singletonList("Notch"))); + this.blacklistedPermissions = new HashSet<>(config.getList(configPath + ".blacklisted-permissions", Collections.singletonList("*"))); } @Override @@ -33,11 +37,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -46,9 +45,16 @@ public void disable() { private void checkForIllegalOp(Player player) { if (allowedOperators.contains(player.getName())) return; - if (player.isOp() || player.hasPermission("*")) { + if (player.isOp()) { + if (shouldLog) warn(player.getName() + " is not in the operators whitelist. Removing operator status."); player.setOp(false); - if (logIsEnabled) warn("Deopped illegally opped player '"+player.getName()+"'."); + } + + for (String permission : blacklistedPermissions) { + if (AnarchyExploitFixes.permissions().permissionValue(player, permission) == TriState.TRUE) { + if (shouldLog) warn(player.getName() + " was found with an illegal permission: '" + permission + "'. Setting it explicitly FALSE."); + AnarchyExploitFixes.permissions().setPermission(player, permission, TriState.FALSE); + } } } @@ -72,7 +78,7 @@ private void onChat(AsyncPlayerChatEvent event) { checkForIllegalOp(event.getPlayer()); } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.LOWEST) // Ensure this runs first private void onCommand(PlayerCommandPreprocessEvent event) { checkForIllegalOp(event.getPlayer()); } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/MapSpam.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/MapSpam.java index 673b5d31f..2e0c4b6b4 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/MapSpam.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/MapSpam.java @@ -4,7 +4,7 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.modules.AEFModule; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -23,49 +23,49 @@ public class MapSpam extends AEFModule implements Listener { - private final Cache trackedPlayers; private final long cooldownMillis; private final int mapCreateLimit; private final boolean shouldNotifyPlayers; + private Cache trackedPlayers; + public MapSpam() { - super("preventions.prevent-map-reset-spam"); - config.addComment(configPath + ".enable", + super("preventions.prevent-map-reset-spam", false, "Puts a cooldown on creating maps so players cant reset\n" + - "map arts that easily.\n" + - "Only needed on versions below 1.12 and lower.\n" + - "Bypass permission: " + AEFPermission.BYPASS_MAP_SPAM.string()); + "map arts that easily.\n" + + "Only needed on versions below 1.12 and lower.\n" + + "Bypass permission: " + AEFPermission.BYPASS_MAP_SPAM.node()); this.shouldNotifyPlayers = config.getBoolean(configPath + ".notify-players", true, "Sends a message to players telling them how many maps\n" + "they can create per time"); this.cooldownMillis = TimeUnit.MINUTES.toMillis(Math.max(1, config.getInt(configPath + ".cooldown-time-in-minutes", 60))); - this.trackedPlayers = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cooldownMillis)).build(); this.mapCreateLimit = config.getInt(configPath + ".max-amount-of-maps-per-time", 4); } @Override public void enable() { + trackedPlayers = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cooldownMillis)).build(); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (trackedPlayers != null) { + trackedPlayers.invalidateAll(); + trackedPlayers.cleanUp(); + trackedPlayers = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) private void onPlayerInteract(PlayerInteractEvent event) { if (event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) return; final ItemStack mapItem = event.getItem(); - if (mapItem == null || mapItem.getType() != XMaterial.MAP.parseMaterial()) return; + if (mapItem == null || mapItem.getType() != XMaterial.MAP.get()) return; final Player player = event.getPlayer(); - if (player.hasPermission(AEFPermission.BYPASS_MAP_SPAM.string())) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), AEFPermission.BYPASS_MAP_SPAM.node()).toBoolean()) return; MapCreations mapCreations = trackedPlayers.get(player.getUniqueId(), k -> new MapCreations()); long currentTime = System.currentTimeMillis(); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/NetherRoof.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/NetherRoof.java index 7a2150d75..dd296efbe 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/NetherRoof.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/NetherRoof.java @@ -2,18 +2,16 @@ import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.enums.AEFPermission; import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.CachingPermTool; import me.xginko.aef.utils.LocationUtil; +import me.xginko.aef.utils.MaterialUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import org.bukkit.entity.Vehicle; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; @@ -29,8 +27,8 @@ public class NetherRoof extends AEFModule implements Listener { private final boolean safe_teleport_enabled; public NetherRoof() { - super("preventions.prevent-nether-roof"); - config.addComment(configPath + ".enable", "Prevent players from going above the nether roof."); + super("preventions.prevent-nether-roof", true, + "Prevent players from going above the nether roof."); this.safe_teleport_enabled = config.getBoolean(configPath + ".safely-teleport-players", true); } @@ -39,11 +37,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -53,7 +46,7 @@ public void disable() { private void onTeleport(PlayerTeleportEvent event) { if ( LocationUtil.isNetherCeiling(event.getTo()) - && !CachingPermTool.hasPermission(AEFPermission.BYPASS_NETHER_ROOF, event.getPlayer()) + && !AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), AEFPermission.BYPASS_NETHER_ROOF.node()).toBoolean() ) { event.setCancelled(true); } @@ -61,12 +54,11 @@ private void onTeleport(PlayerTeleportEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { - final Player player = event.getPlayer(); if ( - LocationUtil.isNetherCeiling(player.getLocation()) - && !CachingPermTool.hasPermission(AEFPermission.BYPASS_NETHER_ROOF, player) + LocationUtil.isNetherCeiling(event.getPlayer().getLocation()) + && !AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), AEFPermission.BYPASS_NETHER_ROOF.node()).toBoolean() ) { - Location belowCeiling = getBelowCeilLocation(player.getLocation()); + Location belowCeiling = getBelowCeilLocation(event.getPlayer().getLocation()); event.setTo(belowCeiling); createSafespace(belowCeiling); } @@ -74,15 +66,14 @@ private void onPlayerMove(PlayerMoveEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onVehicleMove(VehicleMoveEvent event) { - final Vehicle vehicle = event.getVehicle(); - if (!LocationUtil.isNetherCeiling(vehicle.getLocation())) return; + if (!LocationUtil.isNetherCeiling(event.getVehicle().getLocation())) return; - for (Entity passenger : vehicle.getPassengers()) { + for (Entity passenger : event.getVehicle().getPassengers()) { if (passenger.getType() == EntityType.PLAYER - && CachingPermTool.hasPermission(AEFPermission.BYPASS_NETHER_ROOF, (Player) passenger)) return; + && AnarchyExploitFixes.permissions().permissionValue(passenger, AEFPermission.BYPASS_NETHER_ROOF.node()).toBoolean()) return; } - for (Entity entity : vehicle.getPassengers()) { + for (Entity entity : event.getVehicle().getPassengers()) { if (entity.getType() == EntityType.PLAYER) { this.teleportFromCeiling((Player) entity); } else { @@ -91,20 +82,19 @@ private void onVehicleMove(VehicleMoveEvent event) { } } - vehicle.remove(); + event.getVehicle().remove(); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockPlace(BlockPlaceEvent event) { - final Player player = event.getPlayer(); - if (CachingPermTool.hasPermission(AEFPermission.BYPASS_NETHER_ROOF, player)) return; + if (AnarchyExploitFixes.permissions().permissionValue(event.getPlayer(), AEFPermission.BYPASS_NETHER_ROOF.node()).toBoolean()) return; if (LocationUtil.isNetherCeiling(event.getBlock().getLocation())) { event.setCancelled(true); } - if (LocationUtil.isNetherCeiling(player.getLocation())) { - teleportFromCeiling(player); + if (LocationUtil.isNetherCeiling(event.getPlayer().getLocation())) { + teleportFromCeiling(event.getPlayer()); } } @@ -127,30 +117,30 @@ private void createSafespace(Location location) { // Check block above for liquid or falling block Block blockAboveHead = location.clone().add(0, 2, 0).getBlock(); - if (isUnsafe(blockAboveHead) && blockAboveHead.getType() != XMaterial.NETHER_PORTAL.parseMaterial()) - blockAboveHead.setType(XMaterial.NETHERRACK.parseMaterial(), false); + if (isUnsafe(blockAboveHead) && blockAboveHead.getType() != XMaterial.NETHER_PORTAL.get()) + blockAboveHead.setType(XMaterial.NETHERRACK.get(), false); // Create an air pocket for the player Block blockAtPlayerLegs = location.getBlock(); - if (blockAtPlayerLegs.getType() != Material.AIR && blockAtPlayerLegs.getType() != XMaterial.NETHER_PORTAL.parseMaterial()) - blockAtPlayerLegs.setType(Material.AIR, false); + if (!MaterialUtil.AIR.contains(blockAtPlayerLegs.getType()) && blockAtPlayerLegs.getType() != XMaterial.NETHER_PORTAL.get()) + blockAtPlayerLegs.setType(XMaterial.AIR.get(), false); Block blockAtPlayerTorso = blockAtPlayerLegs.getRelative(BlockFace.UP); - if (blockAtPlayerTorso.getType() != Material.AIR && blockAtPlayerTorso.getType() != XMaterial.NETHER_PORTAL.parseMaterial()) - blockAtPlayerTorso.setType(Material.AIR, false); + if (!MaterialUtil.AIR.contains(blockAtPlayerTorso.getType()) && blockAtPlayerTorso.getType() != XMaterial.NETHER_PORTAL.get()) + blockAtPlayerTorso.setType(XMaterial.AIR.get(), false); // Check all sides of air pocket for liquids and fill with netherrack for (int i = 0; i < 2; i++) { Block airPocketBlock = blockAtPlayerLegs.getRelative(BlockFace.UP, i); for (BlockFace face : CARDINAL_FACES) { Block around = airPocketBlock.getRelative(face); - if (isUnsafe(around)) around.setType(XMaterial.NETHERRACK.parseMaterial(), false); + if (isUnsafe(around)) around.setType(XMaterial.NETHERRACK.get(), false); } } // Create block below feet if not solid Block blockBelowFeet = blockAtPlayerLegs.getRelative(BlockFace.DOWN); - if (isUnsafe(blockBelowFeet) || blockBelowFeet.getType().equals(XMaterial.NETHER_PORTAL.parseMaterial())) - blockBelowFeet.setType(XMaterial.NETHERRACK.parseMaterial(), true); + if (isUnsafe(blockBelowFeet) || blockBelowFeet.getType().equals(XMaterial.NETHER_PORTAL.get())) + blockBelowFeet.setType(XMaterial.NETHERRACK.get(), true); } private static boolean isUnsafe(Block block) { diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/PreventNonSurvival.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/PreventNonSurvival.java deleted file mode 100755 index 4cf950c46..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/PreventNonSurvival.java +++ /dev/null @@ -1,88 +0,0 @@ -package me.xginko.aef.modules.preventions; - -import me.xginko.aef.modules.AEFModule; -import org.bukkit.GameMode; -import org.bukkit.entity.HumanEntity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryEvent; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -public class PreventNonSurvival extends AEFModule implements Listener { - - private final Set allowedGamemodePlayers; - private final boolean logIsEnabled; - - public PreventNonSurvival() { - super("preventions.prevent-non-survival-players"); - config.addComment(configPath + ".enable", - "Checks if player is in survival and if not, puts him back into survival. \n" + - "Useful if you had a backdoor incident."); - this.logIsEnabled = config.getBoolean(configPath + ".log", true); - this.allowedGamemodePlayers = new HashSet<>(config.getList(configPath + ".whitelisted-players", - Collections.singletonList("Notch"))); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - private void checkForIllegalGamemode(HumanEntity player) { - if (allowedGamemodePlayers.contains(player.getName())) return; - - if (player.getGameMode() != GameMode.SURVIVAL) { - player.setGameMode(GameMode.SURVIVAL); - if (logIsEnabled) warn("Changed gamemode of '"+player.getName()+"' back to survival."); - } - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onInventory(InventoryEvent event) { - checkForIllegalGamemode(event.getView().getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onJoin(PlayerJoinEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onLeave(PlayerQuitEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onMove(PlayerMoveEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST) - private void onChat(AsyncPlayerChatEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.HIGHEST) - private void onCommand(PlayerCommandPreprocessEvent event) { - checkForIllegalGamemode(event.getPlayer()); - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonExplodePermBlockRemoval.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonExplodePermBlockRemoval.java index 199b75d0d..10853c09d 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonExplodePermBlockRemoval.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonExplodePermBlockRemoval.java @@ -1,8 +1,8 @@ package me.xginko.aef.modules.preventions.blockbreak; +import com.cryptomorin.xseries.XMaterial; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.MaterialUtil; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.event.EventHandler; @@ -20,7 +20,7 @@ public class PistonExplodePermBlockRemoval extends AEFModule implements Listener private final Set whitelistedWorlds; public PistonExplodePermBlockRemoval() { - super("preventions.permanent-block-breaking.by-exploding-pistons"); + super("preventions.permanent-block-breaking.by-exploding-pistons", true); this.whitelistedWorlds = new HashSet<>(config.getList(configPath + ".whitelisted-worlds", Collections.singletonList("example_world_name"))); } @@ -30,11 +30,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -66,6 +61,6 @@ private void onEntityExplode(EntityExplodeEvent event) { // Schedule a single delayed task to remove those blocks silently plugin.getServer().getScheduler().runTaskLater(plugin, () -> - pistons_that_could_break_indestructible_blocks.forEach(block -> block.setType(Material.AIR)), 5L); + pistons_that_could_break_indestructible_blocks.forEach(block -> block.setType(XMaterial.AIR.get())), 5L); } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonPlaceWhileRetractPermBlockRemoval.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonPlaceWhileRetractPermBlockRemoval.java index 2a4c0df86..a60ba7f46 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonPlaceWhileRetractPermBlockRemoval.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/PistonPlaceWhileRetractPermBlockRemoval.java @@ -17,7 +17,7 @@ public class PistonPlaceWhileRetractPermBlockRemoval extends AEFModule implement private final Set whitelistedWorlds; public PistonPlaceWhileRetractPermBlockRemoval() { - super("preventions.permanent-block-breaking.by-placing-piston-on-retract"); + super("preventions.permanent-block-breaking.by-placing-piston-on-retract", true); this.whitelistedWorlds = new HashSet<>(config.getList(configPath + ".whitelisted-worlds", Collections.singletonList("example_world_name"))); } @@ -27,11 +27,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/StructureGrowPermBlockRemoval.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/StructureGrowPermBlockRemoval.java index eb29574f2..c5d6ad1c9 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/StructureGrowPermBlockRemoval.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/blockbreak/StructureGrowPermBlockRemoval.java @@ -14,8 +14,7 @@ public class StructureGrowPermBlockRemoval extends AEFModule implements Listener { public StructureGrowPermBlockRemoval() { - super("preventions.permanent-block-breaking.by-growing-structures"); - config.addComment(configPath + ".enable", + super("preventions.permanent-block-breaking.by-growing-structures", true, "Prevents removal of permanent blocks by growing structures \n" + "like mushrooms into them."); } @@ -25,11 +24,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/EndPortalDestruction.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/EndPortalDestruction.java index d5ed97c98..f16f837cc 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/EndPortalDestruction.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/EndPortalDestruction.java @@ -31,7 +31,7 @@ public class EndPortalDestruction extends AEFModule implements Listener { private final boolean logIsEnabled; public EndPortalDestruction() { - super("preventions.portals.prevent-destroying-end-portals"); + super("preventions.portals.prevent-destroying-end-portals", true); this.logIsEnabled = config.getBoolean(configPath + ".log", true); this.endBedrockProtectRadius = config.getInt(configPath + ".end.bedrock-protection-radius-blocks", 8); this.pillars = config.getList(configPath + ".end.pillar-blocks", @@ -67,11 +67,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -87,14 +82,14 @@ private void onBlockDispense(BlockDispenseEvent event) { private boolean isNearEndPortal(Block dispenser) { for (BlockFace face : BlockFace.values()) { - if (dispenser.getRelative(face).getType() == XMaterial.END_PORTAL.parseMaterial()) return true; + if (dispenser.getRelative(face).getType() == XMaterial.END_PORTAL.get()) return true; } return false; } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerBucketEvent(PlayerBucketEmptyEvent event) { - if (event.getBlockClicked().getRelative(event.getBlockFace()).getType() == XMaterial.END_PORTAL.parseMaterial()) { + if (event.getBlockClicked().getRelative(event.getBlockFace()).getType() == XMaterial.END_PORTAL.get()) { event.setCancelled(true); if (logIsEnabled) info("Prevented "+event.getPlayer().getName()+" from destroying an end portal!"); } @@ -153,7 +148,7 @@ private void onPistonExplode(EntityExplodeEvent event) { }); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> - pistons_that_could_remove_protected.forEach(block -> block.setType(Material.AIR)), 5); + pistons_that_could_remove_protected.forEach(block -> block.setType(XMaterial.AIR.get())), 5); } private boolean isWithinEndProtectedRadius(Location location) { @@ -162,6 +157,6 @@ private boolean isWithinEndProtectedRadius(Location location) { } private boolean isEndPortal(Material material) { - return material == XMaterial.END_PORTAL.parseMaterial() || material == XMaterial.END_PORTAL_FRAME.parseMaterial(); + return material == XMaterial.END_PORTAL.get() || material == XMaterial.END_PORTAL_FRAME.get(); } } \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventAllEntitiesInPortals.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventAllEntitiesInPortals.java index e7859cb45..114085031 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventAllEntitiesInPortals.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventAllEntitiesInPortals.java @@ -11,8 +11,8 @@ public class PreventAllEntitiesInPortals extends AEFModule implements Listener { public PreventAllEntitiesInPortals() { - super("preventions.portals.prevent-all-entities-in-portals"); - config.addComment(configPath, "Only enable if you must. Does not affect players."); + super("preventions.portals.prevent-all-entities-in-portals", false, + "Only enable if you must. Does not affect players."); } @Override @@ -20,11 +20,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventPortalTraps.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventPortalTraps.java index b975a96ee..0f922be20 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventPortalTraps.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventPortalTraps.java @@ -15,8 +15,7 @@ public class PreventPortalTraps extends AEFModule implements Listener { private final long tpBackDelay; public PreventPortalTraps() { - super("preventions.portals.prevent-portal-traps"); - config.addComment(configPath + ".enable", + super("preventions.portals.prevent-portal-traps", false, "Teleports a player back to the original location if they have been\n" + "standing in a portal for too long."); this.tpBackDelay = config.getInt(configPath + ".wait-time-until-tp-back-in-seconds", 10) * 20L; @@ -27,11 +26,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -41,9 +35,9 @@ public void disable() { private void onPortal(PlayerPortalEvent event) { final Player player = event.getPlayer(); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> { - if (player.getLocation().getBlock().getType() == XMaterial.NETHER_PORTAL.parseMaterial()) { + if (player.getLocation().getBlock().getType() == XMaterial.NETHER_PORTAL.get()) { player.teleport(event.getFrom()); - player.playSound(player.getLocation(), XSound.BLOCK_PORTAL_TRAVEL.parseSound(), 1.0F, 1.0F); + player.playSound(player.getLocation(), XSound.BLOCK_PORTAL_TRAVEL.get(), 1.0F, 1.0F); } }, tpBackDelay); } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventProjectilesInPortals.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventProjectilesInPortals.java index 452d6468b..e0ee080ee 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventProjectilesInPortals.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventProjectilesInPortals.java @@ -11,8 +11,8 @@ public class PreventProjectilesInPortals extends AEFModule implements Listener { public PreventProjectilesInPortals() { - super("preventions.portals.prevent-projectiles-in-portals"); - config.addComment(configPath, "Prevents a lag exploit. Might disable some chunk loader designs."); + super("preventions.portals.prevent-projectiles-in-portals", false, + "Prevents a lag exploit. Might disable some chunk loader designs."); } @Override @@ -20,11 +20,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventSpecificEntitiesInPortals.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventSpecificEntitiesInPortals.java index 61f9ed15d..218e7b3be 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventSpecificEntitiesInPortals.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/portals/PreventSpecificEntitiesInPortals.java @@ -1,5 +1,6 @@ package me.xginko.aef.modules.preventions.portals; +import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; @@ -8,25 +9,35 @@ import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityPortalEvent; -import java.util.Arrays; import java.util.EnumSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; public class PreventSpecificEntitiesInPortals extends AEFModule implements Listener { private final Set forbiddenTypes; public PreventSpecificEntitiesInPortals() { - super("preventions.portals.prevent-specific-types"); - config.addComment(configPath + ".enable", + super("preventions.portals.prevent-specific-types", true, "Configure entities here that you suspect might be used in a dupe \n" + "with portals. \n" + "CAUTION: Will kill the entity on folia due to broken portal event. \n" + "There is sadly no other efficient way."); - this.forbiddenTypes = config.getList(configPath + ".entities", - Arrays.asList("DROPPED_ITEM", "FIREWORK", "PRIMED_TNT", "THROWN_EXP_BOTTLE", "EXPERIENCE_ORB", "ARMOR_STAND"), + List defaults = Stream.of( + XEntityType.ITEM, + XEntityType.FIREWORK_ROCKET, + XEntityType.TNT, + XEntityType.EXPERIENCE_BOTTLE, + XEntityType.EXPERIENCE_ORB, + XEntityType.ARMOR_STAND) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList()); + this.forbiddenTypes = config.getList(configPath + ".entities", defaults, "Defaults prevent common lag methods.") .stream() .map(configuredType -> { @@ -46,11 +57,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", true); - } - @Override public void disable() { HandlerList.unregisterAll(this); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/DisableWitherSkulls.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/DisableWitherSkulls.java deleted file mode 100755 index 890ff9c3d..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/DisableWitherSkulls.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.xginko.aef.modules.preventions.withers; - -import com.cryptomorin.xseries.XEntityType; -import me.xginko.aef.modules.AEFModule; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.ProjectileLaunchEvent; - -public class DisableWitherSkulls extends AEFModule implements Listener { - - public DisableWitherSkulls() { - super("preventions.withers.disable-withers-from-shooting-skulls"); - config.addComment(configPath, "Prevents wither skulls from being shot."); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, false); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onProjectileLaunch(ProjectileLaunchEvent event) { - if (event.getEntityType() == XEntityType.WITHER_SKULL.get()) { - event.setCancelled(true); - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RateLimitWitherSkulls.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RateLimitWitherSkulls.java index 81d75d4a1..4bd359502 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RateLimitWitherSkulls.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RateLimitWitherSkulls.java @@ -15,38 +15,49 @@ public class RateLimitWitherSkulls extends AEFModule implements Listener { - private final ExpiringSet targetingPlayers, targetingOther, notTargeting; + private final long playerCooldownMillis, otherCooldownMillis, notargetCooldownMillis; + + private ExpiringSet targetingPlayers, targetingOther, notTargeting; public RateLimitWitherSkulls() { - super("preventions.withers.rate-limit-wither-skulls"); - config.addComment(configPath + ".enable", + super("preventions.withers.rate-limit-shooting-skulls", false, "This can help combat lag caused by a ton of wither skulls\n" + "spawning but weakens withers."); - this.targetingPlayers = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".player-target-cooldown-in-ticks", 20, - "Cooldown until another skull will be shot at a player")) * 50L)); - this.targetingOther = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".other-target-cooldown-in-ticks", 40, - "Cooldown until another skull can be shot at anything \n" + - "else other than a player.")) * 50L)); - this.notTargeting = new ExpiringSet<>(Duration.ofMillis(Math.max(1, - config.getInt(configPath + ".no-target-cooldown-in-ticks", 100, - "Cooldown when wither has no target")) * 50L)); + this.playerCooldownMillis = Math.max(1, config.getInt(configPath + ".player-target-cooldown-in-ticks", 20, + "Cooldown until another skull will be shot at a player")) * 50L; + this.otherCooldownMillis = Math.max(1, config.getInt(configPath + ".other-target-cooldown-in-ticks", 40, + "Cooldown until another skull can be shot at anything \n" + + "else other than a player.")) * 50L; + this.notargetCooldownMillis = Math.max(1, config.getInt(configPath + ".no-target-cooldown-in-ticks", 100, + "Cooldown when wither has no target")) * 50L; } @Override public void enable() { + targetingPlayers = new ExpiringSet<>(Duration.ofMillis(playerCooldownMillis)); + targetingOther = new ExpiringSet<>(Duration.ofMillis(otherCooldownMillis)); + notTargeting = new ExpiringSet<>(Duration.ofMillis(notargetCooldownMillis)); plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); + if (targetingPlayers != null) { + targetingPlayers.clear(); + targetingPlayers.cleanUp(); + targetingPlayers = null; + } + if (targetingOther != null) { + targetingOther.clear(); + targetingOther.cleanUp(); + targetingOther = null; + } + if (notTargeting != null) { + notTargeting.clear(); + notTargeting.cleanUp(); + notTargeting = null; + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveAllSkullsPeriodically.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveAllSkullsPeriodically.java deleted file mode 100755 index 341a7fe5e..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveAllSkullsPeriodically.java +++ /dev/null @@ -1,42 +0,0 @@ -package me.xginko.aef.modules.preventions.withers; - -import me.xginko.aef.modules.AEFModule; -import org.bukkit.World; -import org.bukkit.entity.WitherSkull; -import org.bukkit.scheduler.BukkitTask; - -public class RemoveAllSkullsPeriodically extends AEFModule implements Runnable { - - private final long checkPeriod; - private BukkitTask bukkitTask; - - public RemoveAllSkullsPeriodically() { - super("preventions.withers.remove-flying-wither-skulls.periodically-remove-all-flying-skulls"); - config.addComment(configPath + ".enable", "Enable if a lot of wither skulls at spawn are causing lag."); - this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 80); - } - - @Override - public void enable() { - bukkitTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this, checkPeriod, checkPeriod); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - - @Override - public void disable() { - if (bukkitTask != null) bukkitTask.cancel(); - } - - @Override - public void run() { - for (World world : plugin.getServer().getWorlds()) { - for (WitherSkull entity : world.getEntitiesByClass(WitherSkull.class)) { - entity.remove(); - } - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkunload.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkUnload.java similarity index 55% rename from AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkunload.java rename to AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkUnload.java index 543ffee91..e12c47bfd 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkunload.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkUnload.java @@ -2,20 +2,22 @@ import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.ChunkUtil; +import me.xginko.aef.utils.EntityUtil; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.world.ChunkUnloadEvent; -public class RemoveSkullsOnChunkunload extends AEFModule implements Listener { +public class RemoveSkullsOnChunkUnload extends AEFModule implements Listener { - public RemoveSkullsOnChunkunload() { - super("preventions.withers.remove-flying-wither-skulls.on-chunk-unload"); - config.addComment(configPath, + public RemoveSkullsOnChunkUnload() { + super("preventions.withers.remove-flying-wither-skulls.on-chunk-unload", true, "Removes wither skulls when the chunk gets unloaded.\n" + - "Use if you have a ton of them at spawn and they are causing lag."); + "Use if you have a ton of them at spawn and they are causing lag."); } @Override @@ -23,18 +25,22 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, true); - } - @Override public void disable() { HandlerList.unregisterAll(this); } - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onProjectileLaunch(ProjectileLaunchEvent event) { + if (event.getEntityType() == XEntityType.WITHER_SKULL.get()) { + EntityUtil.setPersistent(event.getEntity(), false); // Don't save skull when chunk unloads + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChunkUnload(ChunkUnloadEvent event) { + if (!ChunkUtil.isEntitiesLoaded(event.getChunk())) return; + for (Entity entity : event.getChunk().getEntities()) { if (entity.getType() == XEntityType.WITHER_SKULL.get()) { entity.remove(); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkload.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkload.java deleted file mode 100755 index f107a2f94..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/RemoveSkullsOnChunkload.java +++ /dev/null @@ -1,46 +0,0 @@ -package me.xginko.aef.modules.preventions.withers; - -import com.cryptomorin.xseries.XEntityType; -import me.xginko.aef.modules.AEFModule; -import org.bukkit.entity.Entity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; - -public class RemoveSkullsOnChunkload extends AEFModule implements Listener { - - public RemoveSkullsOnChunkload() { - super("preventions.withers.remove-flying-wither-skulls.on-chunk-load"); - config.addComment(configPath, - "Removes wither skulls when the chunk gets loaded.\n" + - "Use if you have a ton of them at spawn and they are causing lag."); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath, true); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - private void onChunkLoad(ChunkLoadEvent event) { - if (event.isNewChunk()) return; - - for (Entity entity : event.getChunk().getEntities()) { - if (entity.getType() == XEntityType.WITHER_SKULL.get()) { - entity.remove(); - } - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSkullDropsAtSpawn.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSkullDropsAtSpawn.java new file mode 100755 index 000000000..2d3d11fa1 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSkullDropsAtSpawn.java @@ -0,0 +1,63 @@ +package me.xginko.aef.modules.preventions.withers; + +import com.cryptomorin.xseries.XEntityType; +import io.github.thatsmusic99.configurationmaster.api.ConfigSection; +import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.LocationUtil; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.util.NumberConversions; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WitherSkullDropsAtSpawn extends AEFModule implements Listener { + + private final Map worldsAndTheirRadiuses; + + public WitherSkullDropsAtSpawn() { + super("preventions.withers.disable-item-drops-at-spawn", false, + "Prevents wither skulls from dropping items when they hit a block\n" + + "within a certain radius from 00. Can help with lag."); + Map defaults = new HashMap<>(); + defaults.put("world", 5000); + defaults.put("world_nether", 5000); + defaults.put("world_the_end", 5000); + ConfigSection section = config.getConfigSection(configPath + ".worlds", defaults); + List worlds = section.getKeys(false); + this.worldsAndTheirRadiuses = new HashMap<>(worlds.size()); + for (String world : worlds) { + try { + double radiusSquared = NumberConversions.square(Integer.parseInt(section.getString(world))); + this.worldsAndTheirRadiuses.put(world, radiusSquared); + } catch (NumberFormatException e) { + warn("Radius for world '" + world + "' is not a valid integer."); + } + } + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onEntityExplode(EntityExplodeEvent event) { + if (event.getEntityType() != XEntityType.WITHER_SKULL.get()) return; + if (!worldsAndTheirRadiuses.containsKey(event.getLocation().getWorld().getName())) return; + + if (LocationUtil.getSquaredDistance2DTo00(event.getLocation()) + <= worldsAndTheirRadiuses.get(event.getLocation().getWorld().getName())) { + event.setYield(0); + } + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSpawningAtSpawn.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSummonAtSpawn.java similarity index 63% rename from AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSpawningAtSpawn.java rename to AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSummonAtSpawn.java index 53dd3c3e9..21bef40a9 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSpawningAtSpawn.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/preventions/withers/WitherSummonAtSpawn.java @@ -5,26 +5,25 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.LocationUtil; -import org.bukkit.Location; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.util.NumberConversions; import java.util.HashMap; +import java.util.List; import java.util.Map; -public class WitherSpawningAtSpawn extends AEFModule implements Listener { +public class WitherSummonAtSpawn extends AEFModule implements Listener { - private final Map worldsAndTheirRadiuses = new HashMap<>(); + private final Map worldsAndTheirRadiuses; private final boolean playersShouldBeInformed; - public WitherSpawningAtSpawn() { - super("preventions.withers.disable-wither-spawning-at-spawn"); - config.addComment(configPath + ".enable", + public WitherSummonAtSpawn() { + super("preventions.withers.disable-summon-at-spawn", false, "Disables spawning withers near a configurable radius around\n" + "spawn. Helps if players are generating endless amounts of withers\n" + "to lag the server."); @@ -34,10 +33,12 @@ public WitherSpawningAtSpawn() { defaults.put("world_nether", 5000); defaults.put("world_the_end", 5000); ConfigSection section = config.getConfigSection(configPath + ".worlds", defaults); - for (String world : section.getKeys(false)) { + List worlds = section.getKeys(false); + this.worldsAndTheirRadiuses = new HashMap<>(worlds.size()); + for (String world : worlds) { try { - Integer radius = Integer.parseInt(section.getString(world)); - this.worldsAndTheirRadiuses.put(world, radius); + Double radiusSquared = NumberConversions.square(Integer.parseInt(section.getString(world))); + this.worldsAndTheirRadiuses.put(world, radiusSquared); } catch (NumberFormatException e) { warn("Radius for world '" + world + "' is not a valid integer."); } @@ -49,11 +50,6 @@ public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @Override - public boolean shouldEnable() { - return config.getBoolean(configPath + ".enable", false); - } - @Override public void disable() { HandlerList.unregisterAll(this); @@ -64,20 +60,16 @@ private void onCreatureSpawn(CreatureSpawnEvent event) { if (event.getEntityType() != XEntityType.WITHER_SKULL.get()) return; if (event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.BUILD_WITHER) return; - final Entity entity = event.getEntity(); - final String world = entity.getWorld().getName(); - if (!worldsAndTheirRadiuses.containsKey(world)) return; - - final Integer disabledRadius = worldsAndTheirRadiuses.get(world); - final Location witherLocation = entity.getLocation(); - if (LocationUtil.getDistance2DTo00(witherLocation) > disabledRadius) return; + String worldName = event.getLocation().getWorld().getName(); + if (!worldsAndTheirRadiuses.containsKey(worldName)) return; + if (LocationUtil.getSquaredDistance2DTo00(event.getLocation()) > worldsAndTheirRadiuses.get(worldName)) return; event.setCancelled(true); if (playersShouldBeInformed) { - for (Player nearbyPlayer : witherLocation.getNearbyPlayers(8)) { + for (Player nearbyPlayer : event.getLocation().getNearbyPlayers(8)) { nearbyPlayer.sendMessage(AnarchyExploitFixes.getLang(nearbyPlayer.getLocale()).withers_SpawningDisabledInRadius - .replace("%radius%", disabledRadius.toString())); + .replace("%radius%", worldsAndTheirRadiuses.get(worldName).toString())); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/utils/LocationUtil.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/utils/LocationUtil.java index 2182aaab2..6bdf4a126 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/utils/LocationUtil.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/utils/LocationUtil.java @@ -4,8 +4,9 @@ import org.apache.commons.math3.util.FastMath; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.util.NumberConversions; -public class LocationUtil { +public final class LocationUtil { public static String toString(Location location) { return "[" + location.getWorld().getName() + "] x=" + location.getBlockX() + ", y=" + location.getBlockY() + ", z=" + location.getBlockZ(); @@ -16,10 +17,37 @@ public static boolean isNetherCeiling(Location location) { && location.getY() > AnarchyExploitFixes.config().nether_ceiling_max_y; } + public static double getSquaredDistance2DTo00(Location location) { + return NumberConversions.square(location.getX()) + NumberConversions.square(location.getZ()); + } + public static double getDistance2DTo00(Location location) { return FastMath.hypot(location.getX(), location.getZ()); } + public static double getRelSquaredDistance2D(Location from, Location to) { + double toX = to.getX(); + double toZ = to.getZ(); + double fromX = from.getX(); + double fromZ = from.getZ(); + + final World.Environment toEnv = to.getWorld().getEnvironment(); + final World.Environment fromEnv = from.getWorld().getEnvironment(); + if (toEnv != fromEnv) { + if (fromEnv == World.Environment.NETHER) { + fromX *= 8; + fromZ *= 8; + } + if (toEnv == World.Environment.NETHER) { + toX *= 8; + toZ *= 8; + } + } + + return NumberConversions.square(toX - fromX) + + NumberConversions.square(toZ - fromZ); + } + public static double getRelDistance2D(Location from, Location to) { double toX = to.getX(); double toZ = to.getZ(); @@ -42,6 +70,30 @@ public static double getRelDistance2D(Location from, Location to) { return FastMath.hypot(toX - fromX, toZ - fromZ); } + public static double getRelSquaredDistance3D(Location from, Location to) { + double toX = to.getX(); + double toZ = to.getZ(); + double fromX = from.getX(); + double fromZ = from.getZ(); + + final World.Environment toEnv = to.getWorld().getEnvironment(); + final World.Environment fromEnv = from.getWorld().getEnvironment(); + if (toEnv != fromEnv) { + if (fromEnv == World.Environment.NETHER) { + fromX *= 8; + fromZ *= 8; + } + if (toEnv == World.Environment.NETHER) { + toX *= 8; + toZ *= 8; + } + } + + return NumberConversions.square(toX - fromX) + + NumberConversions.square(from.getY() - to.getY()) + + NumberConversions.square(toZ - fromZ); + } + public static double getRelDistance3D(Location from, Location to) { double toX = to.getX(); double toZ = to.getZ(); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/utils/WorldUtil.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/utils/WorldUtil.java index a1feb5df3..bf1a4cbb4 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/utils/WorldUtil.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/utils/WorldUtil.java @@ -5,7 +5,7 @@ import java.lang.invoke.MethodHandle; -public class WorldUtil { +public final class WorldUtil { private static final MethodHandle GET_MIN_WORLD_HEIGHT, RESPAWNANCHOR_WORKS, BED_WORKS; public static final boolean GET_MIN_WORLD_HEIGHT_AVAILABLE, RESPAWN_ANCHOR_WORKS_AVAILABLE, BED_WORKS_AVAILABLE; diff --git a/AnarchyExploitFixesLegacy/src/main/resources/config.yml b/AnarchyExploitFixesLegacy/src/main/resources/config.yml deleted file mode 100644 index e4da420d9..000000000 --- a/AnarchyExploitFixesLegacy/src/main/resources/config.yml +++ /dev/null @@ -1,2056 +0,0 @@ -plugin-version: 2.7.2 -server-version: 'git-Paper-1620 (MC: 1.12.2)' - -############## -# Language # -############## -language: - # The default language that will be used if auto-language is false - # or no matching language file was found. - default-language: en_us - # If set to true, will display messages based on client language - auto-language: true - -############# -# General # -############# -general: - # The time in ticks (1 sec = 20 ticks) a checked tps will be cached - # by the plugin. - max-tps-check-interval-in-ticks: 20 - # In case packet modules are causing trouble, you can disable them here. - disable-all-packet-listeners: false - # The Y-level at which the nether ceiling generates the last layer - # of bedrock on your server. - nether-ceiling-y: 127 - # If you see this config option, AEF is unable to get the minimum height - # of your worlds from the API. - # Please enter them here manually for each world you're currently using. - # Use the exact same name as your world folder. - world-min-heights: - world: 0 - world_the_end: 0 - world_nether: 0 - # A server restart is required when changing a command's enable status! - commands: - say: - enable: false - format: '&7Server: &6%message%' - help: - # Help command that shows a small command overview for players. - enable: false - toggleconnectionmsgs: - # If you don't use join leave/messages, you can set this to false. - enable: true - -################### -# Miscellaneous # -################### -misc: - join-leave-messages: - # If you want to hide yourself or someone else when logging - # into the game, use these permissions: - # aef.silentJoin, aef.silentLeave - enable: true - # If set to true, players will see join/leave messages by default - # and enter /toggleconnectionmsgs to disable them. - # If set to false will work the other way around. - connection-messages-on-by-default: true - show-in-console: false - first-join-messages: - # Configure message in lang folder. - # You can hide yourself and other players using the permission: - # aef.silentJoin - enable: false - show-in-console: true - kicks: - # Configure mask message in lang folder. - mask-kick-messages: false - prevent-message-kick: - # Cancels the kick for specific kick messages. - enable: false - kick-messages-to-listen-to: - - Kicked for spamming - - Stop spamming! - -########## -# Chat # -########## -chat: - command-whitelist: - # This will make it pretty much impossible to find your plugins as - # only the commands you specify will be able to work. - # Allow bypass using permission: aef.bypass.commandwhitelist - enable: true - # Will show logs when a command was denied. - log: false - # Recommended to use when on 1.12. Otherwise only use if you're having issues. - use-packets: true - # Add all commands you WANT your players to be able to access - # WITHOUT the '/'. Not case sensitive. - whitelisted-commands: - - help - - vote - - kill - - discord - - togglechat - - toggleconnectionmsgs - - toggletells - - togglewhispering - - toggleprivatemsgs - - ignore - - ignorelist - - ignorehard - - toggledeathmsg - - dmt - - worldstats - - stats - - tps - - msg - - whisper - - w - - m - - t - - pm - - tell - - r - - reply - - last - # Add all subcommands you DON'T want your players to be able - # to access. Case sensitive! - blacklisted-subcommands: - - help about - - vote List - - vote Best - - vote Total - - worldstats reload - - stats reload - prevent-scanning-server-plugins: - # Prevents hacked clients running .plugins to find out what plugins - # the server is using. - # Recommended to use in combination with command whitelist. - enable: true - -############ -# Elytra # -############ -elytra: - # NOTE: Set nocheatplus horizontal elytra settings to 500 or higher. - elytra-speed: - # Time in ticks that a chunk has to have been inhabited to count as old chunk. - # Note that the time is incremented once per tick per player within mob spawning - # distance of a chunk. - old-chunk-inhabited-ticks: 200 - # The period in millis players will be checked to determine their speed. - # If you have lagging players with consistent high ping, you can increase this number. - check-period-millis: 500 - # If set to false, will only calculate 2-Dimensional speed - # without taking height changes into consideration. - calculate-3D-speed: true - # Display info in Actionbar while flying. - display-actionbar: true - # Inform flying player if they are in old or new chunks. - display-chunk-info-in-actionbar: true - # Plays XP pickup sound to alert players when theyre going - # above the limit. - play-sound-when-too-fast: true - sound: ENTITY_EXPERIENCE_ORB_PICKUP - # Recommended to leave false if you dont experience any issues. - teleport-instead-of-canceling-movement: false - Global-Settings: - # Global settings. If nothing else is enabled, this will be used for all environments. - enable: true - # Can be slow with a lot of players. Enable only if needed. - use-bypass-permission: false - deny-elytra-usage: false - speed-old-chunks: 1.81 - speed-new-chunks: 1.81 - enable-bursting: true - burst-speed-old-chunks: 5.0 - burst-speed-old-chunk-TPS: 18.0 - burst-speed-new-chunks: 3.12 - burst-speed-new-chunk-TPS: 19.0 - deny-elytra-on-low-TPS: true - deny-elytra-TPS: 12.0 - also-remove-elytra-on-low-TPS: true - At-Spawn: - # Use separate values for players at spawn. - enable: false - # Radius in blocks around 00 that should count as spawn. - radius: 3000 - # Can be slow with a lot of players. Enable only if needed. - use-bypass-permission: false - deny-elytra-usage: false - speed-old-chunks: 1.0 - speed-new-chunks: 0.8 - deny-elytra-on-low-TPS: true - deny-elytra-TPS: 10.0 - also-remove-elytra-on-low-TPS: true - Nether-Ceiling: - # Use separate values for players above the nether ceiling. - enable: true - # Can be slow with a lot of players. Enable only if needed. - use-bypass-permission: false - deny-elytra-usage: false - speed-old-chunks: 0.5 - speed-new-chunks: 0.5 - enable-bursting: true - burst-speed-old-chunks: 1.0 - burst-speed-old-chunk-TPS: 18.0 - burst-speed-new-chunks: 1.0 - burst-speed-new-chunk-TPS: 18.0 - deny-elytra-on-low-TPS: true - deny-elytra-TPS: 12.0 - also-remove-elytra-on-low-TPS: true - packet-elytra-fly: - # Patches the future/rusherhack/kamiblue 2b2t elytra fly exploit - patch-packet-elytra-fly: false - # The fly exploit causes the player to constantly toggle gliding. - # If too many glide toggles occur within a timeframe, they are - # most likely using PacketFly. - # Still may trigger false positives when players are jumping and - # sprinting with elytra equipped, so recommended to play around - # with the values. - max-glide-toggles-per-time: 25 - # Time in seconds a elytra open count will be remembered by the plugin. - time-in-seconds: 8 - # Configure message in lang folder. - notify-player-to-disable-packetfly: true - # If enabled, player will be kicked with a message instead of - # getting their elytra dropped. - kick-instead-of-remove-elytra: false - -################## -# Chunk Limits # -################## -chunk-limits: - entity-limits: - dropped-item-limit: - # Limit the amount of dropped items in a chunk to combat lag. - # Be aware this does not prioritize items by value or anything, - # it just deletes whatever happens to get over the limit during - # counting. - enable: false - log-removals: true - max-dropped-items-per-chunk: 200 - # The delay in ticks the plugin will wait after an item in a chunk - # has dropped before the check logic will run. - # This improves performance as there will be no check for each single - # item entity that spawns. - post-item-drop-check-delay: 60 - # The period in ticks in which all loaded chunks should be regularly - # checked. Keep in mind: A lower number provides more accuracy but is - # also worse for performance. - check-period-in-ticks: 800 - # Runs item check when a chunk is loaded. - check-on-chunk-load: true - whitelist-specific-item-types: false - # Check the paper api for correct Material enums: - # https://jd.papermc.io/paper/1.20.6/org/bukkit/Material.html - # Make sure your minecraft version is matching as well. - whitelisted-types: - - BLACK_SHULKER_BOX - - BLUE_SHULKER_BOX - - BROWN_SHULKER_BOX - - CYAN_SHULKER_BOX - - GRAY_SHULKER_BOX - - GREEN_SHULKER_BOX - - LIGHT_BLUE_SHULKER_BOX - - LIME_SHULKER_BOX - - MAGENTA_SHULKER_BOX - - ORANGE_SHULKER_BOX - - PINK_SHULKER_BOX - - PURPLE_SHULKER_BOX - - RED_SHULKER_BOX - - SILVER_SHULKER_BOX - - WHITE_SHULKER_BOX - - YELLOW_SHULKER_BOX - tile-entity-limit: - # Limit the amount of tile entities in a chunk to prevent lag. - enable: false - log-removals: true - max-tile-entities-per-chunk: 100 - check-period-in-ticks: 20 - villager-limit: - enable: false - max-villagers-per-chunk: 25 - log-removals: false - # check all chunks every x ticks. - check-period-in-ticks: 600 - # Professions that are in the top of the list are going to be scheduled - # for removal first. - removal-priority: - - NITWIT - - BUTCHER - - FARMER - - LIBRARIAN - whitelist: - enable: false - professions: - - NITWIT - - BUTCHER - - FARMER - - LIBRARIAN - non-living-limit: - # Limit the amount of non living entities in a chunk to prevent lag. - # Ignores dropped items. - enable: false - log-removals: true - max-non-living-per-chunk: 100 - # 20 ticks = 1 second - check-period-in-ticks: 20 - custom-limit: - # Limit specific entity types per chunk. - enable: false - log-removals: true - # Check all loaded chunks every x ticks. - check-period-in-ticks: 1200 - # Check the paper api for correct EntityType enums: - # https://jd.papermc.io/paper/1.20/org/bukkit/entity/EntityType.html - # Make sure your minecraft version is matching as well. - limited-types: - BAT: 3 - BLAZE: 10 - CAVE_SPIDER: 10 - CHICKEN: 10 - COW: 10 - CREEPER: 10 - DONKEY: 10 - ENDERMAN: 10 - ENDERMITE: 3 - EVOKER: 15 - GUARDIAN: 20 - HORSE: 10 - HUSK: 10 - IRON_GOLEM: 15 - LLAMA: 10 - MAGMA_CUBE: 10 - MULE: 10 - MUSHROOM_COW: 10 - OCELOT: 3 - PARROT: 10 - PIG: 10 - POLAR_BEAR: 5 - RABBIT: 5 - SHEEP: 10 - SILVERFISH: 3 - SKELETON: 10 - SKELETON_HORSE: 10 - SLIME: 10 - SPIDER: 10 - SQUID: 20 - STRAY: 10 - VEX: 15 - VINDICATOR: 15 - WITCH: 15 - WITHER: 16 - WITHER_SKELETON: 10 - WITHER_SKULL: 10 - WOLF: 10 - ZOMBIE: 10 - ZOMBIE_HORSE: 10 - ZOMBIE_VILLAGER: 25 - vehicle-limit: - # Limit the amount of vehicles to prevent some lag machines. - # ex. dispenser that spawns a lot of boats into a single location - # then hitting it, causing all boats to explode in every direction. - enable: false - log-removals: false - max-vehicles-per-chunk: 25 - # 200 ticks = 10 seconds. - check-period-in-ticks: 400 - falling-block-limit: - # Prevent players from placing massive sand chunks, then collapsing - # them to kill the server. - enable: true - log: false - # Removes any falling block if there is more than x blocks actively - # falling in a chunk. - max-falling-gravity-blocks-per-chunk: 60 - # Delay in ticks until the same chunk can be checked again. - # Prevents overchecking, because physics events can be called many - # times in a short time for the same chunk. - chunk-check-delay-in-ticks: 20 - block-limit: - enable: false - # Attempt to prevent ChunkBan / Client FPS Lag - max-blocks-per-chunk: - BANNER: 12 - BEACON: 32 - CHEST: 500 - DISPENSER: 100 - ENCHANTMENT_TABLE: 16 - ENDER_CHEST: 64 - GLOWSTONE: 5000 - PISTON_BASE: 32 - PISTON_EXTENSION: 32 - PISTON_MOVING_PIECE: 32 - PISTON_STICKY_BASE: 32 - SIGN: 8 - SIGN_POST: 8 - SKULL_ITEM: 16 - SLIME_BLOCK: 128 - TRAPPED_CHEST: 200 - WALL_BANNER: 12 - WALL_SIGN: 8 - minecart-limit: - # Limit the amount of minecarts to prevent lag caused by collisions. - enable: false - log-removals: false - max-minecarts-per-chunk: 25 - # 200 ticks = 10 seconds. - check-period-in-ticks: 400 - exp-bottle-limit: - # Prevent players from crashing the server or other players by - # creating a ton of THROWN_EXP_BOTTLE entities, then loading - # them at once. - # Does not limit the EXP_ORBS, just the bottle entities. - enable: true - log: false - # Max in a chunk, doesn't limit the actual xp orbs. - max-exp-bottle-per-chunk: 25 - # 20 ticks = 1 second - check-period-in-ticks: 800 - -##################### -# Lag Preventions # -##################### -lag-preventions: - keep-stash-chunks-loaded: - # Idea by 3b3t admin kumori (Soft1k) - # Improves lag generated by large stash chunks constantly loading and - # unloading by setting them force loaded. This might cause increased ram - # usage, so keep an eye out for that. - # Only works on 1.15+. Will not enable on unsupported versions. - enable: false - log: false - # How many container blocks have to be in a chunk for it to be seen - # as a stash chunk to keep force loaded. - container-block-threshold: 50 - # The time in minutes a stash chunks will be kept force loaded before - # setting it back to normal. - keep-loaded-minutes: 120 - # Set to false if you want to check more blocks than just tile entities. - # Makes the overall speed of the module faster if set to true. - only-check-tile-entities: true - container-types: - - DISPENSER - - CHEST - - FURNACE - - BEACON - - TRAPPED_CHEST - - HOPPER - - DROPPER - - WHITE_SHULKER_BOX - - ORANGE_SHULKER_BOX - - MAGENTA_SHULKER_BOX - - LIGHT_BLUE_SHULKER_BOX - - YELLOW_SHULKER_BOX - - LIME_SHULKER_BOX - - PINK_SHULKER_BOX - - GRAY_SHULKER_BOX - - SILVER_SHULKER_BOX - - CYAN_SHULKER_BOX - - PURPLE_SHULKER_BOX - - BLUE_SHULKER_BOX - - BROWN_SHULKER_BOX - - GREEN_SHULKER_BOX - - RED_SHULKER_BOX - - BLACK_SHULKER_BOX - - BREWING_STAND_ITEM - # Radiuses around spawn in chunks (not blocks) that should not be checked. - # Worlds not on this list are exempt from all checking. - worlds: - world: 100 - world_the_end: 100 - world_nether: 100 - disable-item-drops-during-large-stash-explosions: - # Explodes containers without dropping items after a certain amount - # of exploded containers per chunk. - enable: false - log: false - # How many container blocks in a chunk can be blown up until items - # no longer drop from them. - min-explosions-before-drops-disable: 6 - # The time in seconds to wait after an explosion for another one to happen. - # If no explosion happens within x seconds after the first one, the count - # resets to 0. - time-in-seconds: 3 - container-types: - - DISPENSER - - CHEST - - FURNACE - - BEACON - - TRAPPED_CHEST - - HOPPER - - DROPPER - - BREWING_STAND_ITEM - prevent-lever-spam: - # Rate Limit levers to prevent a lag exploit. - enable: false - show-actionbar: true - kick-player: false - max-lever-usages-per-time: 15 - lever-time-in-ticks: 40 - entity-age-limits: - custom-limits: - # Kill certain entities after a custom amount of ticks lived. - enable: false - log-removals: false - # Check all loaded chunks every x ticks. - check-period-in-ticks: 1200 - # Check the paper api for correct EntityType enums: - # https://jd.papermc.io/paper/1.20/org/bukkit/entity/EntityType.html - # Make sure your minecraft version is matching as well. - limited-types: - ARROW: 120 - FALLING_BLOCK: 160 - SNOWBALL: 100 - SPECTRAL_ARROW: 120 - WITHER_SKULL: 100 - projectile-limit: - # Patches any lag exploit that abuses spawning a ton of projectile entities - # (ex. Snowball exploit).Skips over the following entities: ENDER_PEARL, FISHING_HOOK, WITHER_SKULL - # and ENDER_SIGNAL. You can configure those separately in the custom entity age - # limit section. - enable: false - # (20 ticks = 1 second) Will not touch Ender Pearls - max-alive-time-ticks: 300 - # How frequently we should check all projectiles for their alive time - check-period-seconds: 20 - prevent-flooding-machines: - # Will prevent pistons from pushing waterlogged blocks. - enable: false - delete-waterlogged-blocks: true - anti-shulker-drops: - # Disables shulkers dropping stored items when blown up. - # This helps fix client- and serverside lag when done often and fast. - enable: false - regional-activity: - block-spread: - # Limits blocks spreading or forming based on world conditions within a - # configurable radius and timeframe to help reduce lag by cancelling burst - # activity hotspots. - # - # Examples: - # - # - Snow forming due to a snow storm. - # - Ice forming in a snowy Biome like Taiga or Tundra. - # - Obsidian / Cobblestone forming due to contact with water. - # - Concrete forming due to mixing of concrete powder and water. - # - Mushrooms spreading. - # - Fire spreading. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times a block can form or spread within the configured - # timeframe before activity will be put on cooldown. - block-form-event-limit: 800 - creature-spawn: - # Limits entity spawning activity within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A creature gets spawned naturally, by spawner or other reasons. - # - An entity gets spawned naturally, by spawner or other reasons. - # This does not include tile entities. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of entity spawns within configured timeframe. - spawn-event-limit: 6000 - entity-targeting: - # Limits entities targeting other entities within a configurable radius - # and timeframe to help reduce lag by cancelling burst activity hotspots. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 14.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times an entity can target another entity within the - # configured timeframe before the area will be put on cooldown. - entity-target-event-limit: 8000 - distance-limit: - global-limit: - enable: false - # The max distance no target should exceed. - # You want this to be higher than your highest max distance - # for a specific mob. - max-target-distance: 20.0 - custom-limits: - enable: true - entities: - SKELETON: 6.0 - WITHER: 8.0 - WITHER_SKELETON: 8.0 - ZOMBIE: 6.0 - ZOMBIE_VILLAGER: 10.0 - entity-pathfinding: - # Limits entities deciding to pathfind to a specific location - # within a configurable radius and timeframe to help reduce lag - # by cancelling burst activity hotspots. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 14.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times an entity can decide to start moving - # towards a location within the configured timeframe before the - # area will be put on cooldown. - entity-pathfind-event-limit: 4000 - distance-limit: - global-limit: - enable: false - # The max distance no mob pathfinding should exceed. - # You always want this to be higher than your highest max distance - # for a specific mob. - max-target-distance: 20.0 - custom-limits: - enable: true - entities: - SKELETON: 6.0 - WITHER: 8.0 - WITHER_SKELETON: 8.0 - ZOMBIE: 6.0 - ZOMBIE_VILLAGER: 10.0 - liquid-spread: - # Limits liquid spreading within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A lava block spreading by flowing. - # - A water block spreading by flowing. - # - (optional) A dragon egg is teleporting from one position to another. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 12.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 100.0 - # Maximum number of times liquids are allowed to spread within the configured - # timeframe before they will be put on cooldown. - liquid-spread-event-limit: 2400 - ignore-dragon-egg: true - redstone: - # Limits redstone activity within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A redstone current changes. - # - A redstone block gets powered on. - # - A redstone block gets powered off. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of redstone events within configured timeframe. - redstone-event-limit: 6000 - noteblocks: - # Limits noteblocks being played within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A noteblock is being played through player interaction. - # - A noteblock is being played through a redstone current. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times a noteblock can be played within the configured - # timeframe before they will be put on cooldown. - noteblock-play-limit: 2800 - explosions: - # Limits explosions within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A block exploding. - # - An entity exploding. - # - An entity making the decision to explode. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of explode events within the configured timeframe - # before the region will be put on cooldown. - explode-event-limit: 500 - pistons: - # Limits piston movement within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A piston extends. - # - A piston retracts. - enable: false - log: false - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 6000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 10000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of piston extend and/or retracts within the - # configured timeframe. - piston-movement-limit: 1000 - block-physics: - # Limits block physics within a configurable radius and timeframe - # to help reduce lag by cancelling burst activity hotspots. - # - # Note: - # - # The event used for this check (BlockPhysicsEvent) is a high frequency event, - # it may be called thousands of times per a second on a busy server. - # Where possible the event may also only be called for the "root" block of - # physics updates in order to limit event spam. - # Physics updates that cause other blocks to change their state may not result - # in an event for each of those blocks (usually adjacent). - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of times a physics check can be performed within the configured - # timeframe before they will be put on cooldown. - block-physics-event-limit: 256000 - sculk-sensor: - # Limits sculk activity within a configurable radius and timeframe - # to help reduce lag by cancelling high activity hotspots. - # - # Examples: - # - # - A redstone current changes for a sculk sensor. - # - A physics check is being performed for a sculk sensor. - enable: false - log: true - # The radius in blocks in which activity will be grouped together and measured. - check-radius-blocks: 1500.0 - # The time in milliseconds all related activity will be blocked if it exceeded - # the configured limit. - pause-time-millis: 18000 - # The time in milliseconds before a region and its data will be expired - # if no activity has been detected. - # For proper functionality, needs to be at least as long as your pause time. - data-keep-time-millis: 20000 - # The TPS at which to cancel the physics entirely. - pause-TPS: 10.0 - # The MSPT at which to cancel the physics entirely. - pause-MSPT: 120.0 - # Maximum number of sculk events within configured timeframe. - sculk-event-limit: 800 - sculk-blocks: [] - -############# -# Patches # -############# -patches: - prevent-end-gateway-crash: - # Prevents a crash exploit involving boats and end gateways: - # https://www.youtube.com/watch?v=c5nVBQeYo-I - enable: true - log: true - prevent-redstone-on-trapdoor-crash: - # prevents a powerful crash exploit present in 1.13 - 1.19.3 - enable: false - log: true - max-trapdoor-activations-by-redstone-per-time: 10 - # 1 sec = 20 ticks - time-in-ticks: 30 - # Patches the cow duplication exploit that allows duping cows using shears. - # Only affects lower versions - cow-dupe-patch: false - anti-book-ban: - enable: true - # If set to false, will use UTF-8. - # Charset to use to encode the result of NBTCompound#toString into - # a sequence of bytes. The length of that sequence is then used to - # get the approximate Byte-size of an ItemStack. - # Use the /aef bytesize command to get a better understanding. - use-UTF-16: false - max-book-size: 8000 - # Kicks players when they try to create a book bigger than the limit. - kick-on-too-large-book-edit: true - max-author-chars: 32 - max-title-chars: 32 - max-pages: 100 - max-item-size: 8260 - max-inventory-size: 50674 - # How long in ticks a dropped item's size should be cached after - # checking. - dropped-items-size-cache-ticks: 120 - # How long in ticks a player's inventory size should be cached after - # checking. - player-inventory-size-cache-ticks: 20 - pearl-phase: - # Attempts to patch a pearl phasing exploit by cancelling the teleport - # if the pearl is thrown at or near a specific block. - # At the time of the creation of this module, this is an issue with NoCheatPlus. - enable: false - # How many blocks around the teleport location should be searched - # for potential glitch blocks if the teleport location isn't one itself. - search-radius: 2 - maximum-distance-to-cancel-teleport: 3.0 - glitchy-materials: - - GOLD_PLATE - - IRON_PLATE - - IRON_TRAPDOOR - - PURPUR_SLAB - - STEP - - STONE_PLATE - - STONE_SLAB2 - - TRAP_DOOR - - WEB - - WOOD_PLATE - - WOOD_STEP - prevent-command-sign: - # Patch signs that have run_command NBT tags attached, allowing the - # to run a command with operator permissions on click. - # Recommended to enable if you had a rogue admin or backdoor incident. - enable: false - prevent-multiple-enderdragons: - enable: false - log: true - prevent-fast-world-teleport-crash: - # Prevents crash methods that involve very fast teleporting - # between different worlds in a short time. - enable: true - # Time in milliseconds until an entity can teleport to - # another world again. - teleport-delay-millis: 1000 - log: false - prevent-teleport-coordinate-exploit: - # Patches coordinate exploit for teleportation commands such as /tpa, - # /home AS WELL as respawn exploits. - # This is done by vanishing the player for x ticks before teleporting. - enable: true - min-distance-to-vanish-player: 100 - teleport-vanish-time-in-ticks: 10 - # Removes entities or players if they are invalid, dead or not located - # within a ticking chunk. Not sure if this works. - experimental-godmode-patch: false - prevent-dispenser-crash: - # Prevents dispensers from crashing the server when dispensing - # items out of bounds: https://www.youtube.com/watch?v=XL17P87O6xA - enable: true - log: false - tab-complete-crash-patch: - # Patches two lag exploits and an instant server shutdown exploit that - # works by sending a malicious TabComplete packet that triggers a - # StackOverflowError inside the TagParser class. - enable: true - log: false - kick-player: false - remove-beehive-coordinates: - # Patches an exploit that allows players to obtain another player's - # coordinates by trading them for Beehives or Beenests. - # If the traded item contains any bees, the stored bee's NBT data can - # then be read from the item. - # This data includes, but is not limited to: - # - XYZ coordinates of where the bee has its hive - # - XYZ of the bee's last coordinates before entering it's hive - # - XYZ coordinates of where the bee last visited a flower - # - XYZ coordinates of where the bee was first spawned into existence - # - UID of the world the bee was first spawned into existence - enable: true - # The NBT tags to filter from the item. These are the Keys that hold - # the position data. You may add more tags you want removed here. - tags: - - Pos - - HivePos - - FlowerPos - - Paper.Origin - - Paper.OriginWorld - - WorldUUIDMost - - WorldUUIDLeast - window-click-crash-patch: - # Patches a variety of different lag and crash methods that work - # by sending invalid Window Click packets, causing the server to - # dump error logs until it runs out of memory. - enable: true - log: true - kick-player: false - map-cursor-lag-patch: - # Patches the famous stacked map cursor lag that causes both - # client and server crashes. - enable: true - prevent-nocom-coordinate-exploit: - # Prevents the abusable mechanic used by the infamous "No Comment" - # coordinate exploit, where the server responds to requests that are - # far outside of the sending player's reach, therefore either crashing - # or revealing positions loaded by other players. - # More info on NoCom: https://www.youtube.com/watch?v=elqAh3GWRpA - # This is still useful to keep enabled even if your version is not - # affected by the NoCom vulnerability. - enable: true - max-distance: 24 - log: false - kick-player: false - inventory-lag: - # Checks if a player is requesting unusual amounts of traffic from the server - # using ItemStacks. - # If a player exceeds the limit, they will be put on a cooldown, during which - # they will be very limited in terms of ItemStack or Inventory interactions. - enable: false - # For debug purposes. Don't leave enabled for too long as it is very spammy. - log: false - # Whether to immediately close any open inventory of the player on limit exceed - # Note: Closing has to be scheduled so it will take a bit if the server is heavily - # lagging. - close-open-inventory: true - # The time in millis in which to check if the player exceeded the limit. - # Needs to be at least as long as your lockout duration millis. - byte-data-keep-time-millis: 30000 - rate-limit: - # The limit in bytes the server has sent the server in the form of ItemStacks, - # before the player will be put on a rate-limit. - # Should always be lower than your lockout bytesize limit. - bytesize-limit: 8000000 - # The time in millis in which a player is allowed to open x amounts of windows - # but not more. - timeframe-millis: 2500 - # The amount of windows that can be opened during the timeframe-millis. - max-window-opens-per-timeframe: 2 - lockout: - # The upper limit in bytes a player is allowed to request from the server - # within the configured timeframe before he will be put on cooldown. - # During the cooldown, he will not be able to open any inventory screens - # or interact with items. - bytesize-limit: 24000000 - # The time in milliseconds the player will have to wait before - # being able to open an inventory again after he exceeded the limit. - duration-millis: 15000 - check-packets: - - SET_SLOT - - WINDOW_ITEMS - lectern-crash-patch: - # Patches an instant server crash exploit that involves sending - # an invalid Window Click packet while taking a book out of a Lectern. - enable: true - log: false - kick-player: false - sequence-crash-patch: - # Patches a variety of lag/crash exploits that involves sending packets - # with invalid sequences. - enable: true - log: false - kick-player: false - sign-lag: - # Patches a lag exploit that involves sending specific oversized - # sign edit packets. - enable: true - # How many ticks a player needs to wait to be able to send - # another sign update packet (renaming or writing). - packet-delay-in-ticks: 10 - # Vanilla limit is 384 characters per line, which is too much. - line-character-limit: 80 - # General char limit for all lines combined. - total-char-limit: 384 - log: false - kick-player: false - beehive-crash-patch: - # Patches a server crash exploit exclusive to Purpur servers. - # This exploit works due to PurpurClient having a feature that - # lets clients request stored data of a clicked beehive from - # the server. The server does not check how far the clicked - # beehive is away from the client enabling a malicious sender - # to load chunks very fast at far away locations by telling - # the server it clicked a beehive there. - enable: true - channel: purpur:beehive_c2s - max-distance: 24 - log: false - kick-player: false - prevent-crafting-recipe-lag-exploit: - # Prevent lag or crash caused by flooding the server with - # crafting recipe book requests. This can even be done by hand on - # servers with low specs. Only affects versions < 1.16 - enable: true - # How many ticks a player needs to wait to be able to use - # the crafting recipe book again - crafting-recipe-delay-in-ticks: 5 - log: false - kick-player: false - -############## -# Illegals # -############## -illegals: - remove-placed-blocks: - on-chunkload: - # Remove illegally placed blocks on chunkload. - enable: false - blocks-to-remove: - - COMMAND_CHAIN - - COMMAND - - COMMAND_MINECART - - COMMAND_REPEATING - - BEDROCK - - BARRIER - exempted-worlds: - - exampleworld1 - - exampleworld2 - pause-on-low-TPS: true - pause-TPS: 14.0 - periodically: - enable: false - blocks-to-remove: - - COMMAND_CHAIN - - COMMAND - - COMMAND_MINECART - - COMMAND_REPEATING - - BEDROCK - - BARRIER - exempted-worlds: - - exampleworld1 - - exampleworld2 - check-period-in-seconds: 10 - pause-on-low-TPS: true - pause-TPS: 14.0 - remove-unnatural-spawners-on-chunkload: - enable: false - pause-on-low-TPS: true - pause-TPS: 14.0 - # You can add or remove as much world names here as you want. - natural-spawner-types-per-world: - world: - - SKELETON - - ZOMBIE - - SILVERFISH - - SPIDER - - CAVE_SPIDER - world_the_end: - - SKELETON - - SPIDER - world_nether: - - BLAZE - - MAGMA_CUBE - nbt: - ban-custom-tags: - # Bypass permission: aef.bypass.illegal.nbt.custom - # Deletes items that have one or more of the configured tags. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - # The exact, case sensitive value of the nbt tag. - tags: - - dmg - item-whitelist-enabled: false - use-as-blacklist-instead: false - whitelisted-items: - - GOLDEN_APPLE - impossibly-stored-items: - # Bypass permission: aef.bypass.illegal.nbt.storeditems - # Prevents usage of or deletes storage items that have been pre-filled - # with items using NBT tags. These can only be created by players with - # creative access. - # Most commonly dispensers, droppers and chests containing kit shulkers - # are created but there are more combinations possible. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - # The exact name of the nbt tag that signals items are stored inside. - tag: BlockEntityTag - check-stored-items: false - storage-types: - - BEACON - - BREWING_STAND_ITEM - - CHEST - - DISPENSER - - DROPPER - - FURNACE - - HOPPER - - TRAPPED_CHEST - command-items: - # Bypass permission: aef.bypass.illegal.nbt.commanditem - # Deletes items with commands in their NBT data that run as operator. - # These can only be created by players with creative access. - # Most common items are books, since it allows storing multiple commands. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - enchantments: - inapplicable-enchants: - # Bypass permission: aef.bypass.illegal.enchants.inapplicable - # Reverts or prevents usage of ItemStacks with Enchantments that - # cannot be applied to that ItemStack in vanilla survival minecraft. - # Examples: A helmet with sharpness or a block of stone with fortune. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - item-whitelist-enabled: true - use-as-blacklist-instead: false - whitelisted-items: - - GOLDEN_APPLE - higher-enchants: - # Bypass permission: aef.bypass.illegal.enchants.higher - # Reverts or prevents usage of ItemStacks with Enchantments higher - # than the natural, in vanilla survival obtainable level (aka 32ks / 255s). - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - only-specific-enchants: false - specific-enchants: - - DIG_SPEED - item-whitelist-enabled: true - use-as-blacklist-instead: false - whitelisted-items: - - GOLDEN_APPLE - incompatible-enchants: - # Bypass permission: aef.bypass.illegal.enchants.incompatible - # Reverts or prevents usage of ItemStacks with Enchantments that - # cannot coexist in vanilla survival minecraft. - # Examples: A bow with mending and infinity or armor with every - # protection enchantment. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - item-whitelist-enabled: true - use-as-blacklist-instead: false - whitelisted-items: - - BOW - ban-player-heads: - # Bypass permission: aef.bypass.illegal.playerhead - # Deletes or prevents usage of player heads. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - # Will delete shulker/bundle if they contain any player heads. - check-stored-items: false - ban-specific-materials: - # Bypass permission: aef.bypass.illegal.bannedmaterial - # Prevents usage of or deletes items with material that you do not want - # your players to be able to use. - # Useful if your players have blocks that shouldn't be obtainable in survival. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - banned-materials: - - COMMAND_CHAIN - - COMMAND - - COMMAND_MINECART - - COMMAND_REPEATING - - BEDROCK - - BARRIER - - STRUCTURE_BLOCK - - STRUCTURE_VOID - - ENDER_PORTAL_FRAME - - ENDER_PORTAL - - PORTAL - potions: - # Bypass permission: aef.bypass.illegal.potions - # Prevents usage of or reverts items with any attribute modifiers - # or item flags. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - ban-spawn-eggs: - # Bypass permission: aef.bypass.illegal.spawnegg - # Deletes or prevents usage of spawn eggs. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - # If remove-spawn-eggs is set to true Will delete shulker/bundle - # should they contain any spawneggs. - check-stored-items: false - whitelisted-items: - - MONSTER_EGG - data-values: - custom-data-values: - # 1.12 Only. Bypass permission: aef.bypass.illegal.data.custom - # Deletes items with configured illegal MaterialData values. - # Use '/aef datavalue' ingame while holding an item to add the - # specific value here. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - data-values: - - SuperIllegalItem(0) - item-whitelist-enabled: false - use-as-blacklist-instead: false - whitelisted-items: - - GOLDEN_APPLE - illegal-golden-apples: - # 1.12 Only. Bypass permission: aef.bypass.illegal.data.apple - # Deletes apples with illegal MaterialData values. Will use the - # API to determine what a natural value looks like. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - check-stored-items: false - banned-item-names: - # Bypass permission: aef.bypass.illegal.bannedname - # Resets an item's name (or deletes the item) if it matches one of - # the configured regexes. - # Regexes can be complex. Use a tool like https://regex101.com/ or - # ChatGPT for good results. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - # Will delete the item instead of resetting the name. - delete-item: false - regex: - - (?i)illegalstring - whitelisted-items: - - DIRT - illegally-stacked-items: - # Bypass permission: aef.bypass.illegal.overstacked - # Prevents usage of or reverts items with a higher or lower - # stack size than their vanilla limit. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - item-whitelist-enabled: false - use-as-blacklist-instead: true - check-stored-items: false - whitelisted-items: - - TOTEM - revert-unbreakables: - # Bypass permission: aef.bypass.illegal.unbreakable - # Deletes and prevents usage of unbreakable items. - # This can be anything from items with illegal damage attributes to - # Metadata/NBT tags. - # Note: Due to the limitations of the API, we can only fully prevent - # usage of these items by deleting them. - enable: false - # Available options: - # STRICT - Deletes or reverts illegals even on chest open - # ACTION_ON_USE - Deletes or reverts illegals when interacted with - # PREVENT_USE_ONLY - Only prevents usage of illegals if possible - handling: PREVENT_USE_ONLY - # Enable this if you have problems with the plugin removing items from chest guis. - gui-plugins-supported: false - # Prevents Hopper32k mechanic of placing a shulker containing illegals on top - # of a hopper, then using the illegal out of the hopper's inventory. - # WARNING: Hooks into InventoryMoveItemEvent, which can become VERY resource - # intense as the event fires in high frequencies as soon as players start using - # farms or item sorters. Recommended to leave off if not necessary. - prevent-hopper32k-mechanic: false - check-on-chunkload: - # WARNING: CHECKING ON CHUNKLOAD IS NOT RECOMMENDED AS IT IS VERY RESOURCE INTENSE. - # BE VERY SURE YOU ACTUALLY NEED THIS. - # Iterates over all blocks in a chunk when it is loaded and checks any inventories - # for illegals. If a container with illegals is found, the container will be REMOVED. - enable: false - # If set to true, immediately replaces the container with air. Otherwise, will try - # to handle items separately. - remove-container: false - # The time in milliseconds to wait before performing another check, - # if a check was positive. Helps with lag resulting from repeatedly - # checking illegals. - check-rate-limit-millis: 3000 - item-whitelist-enabled: false - use-as-blacklist-instead: false - # Will delete shulkers and bundles if they contain unbreakables. - check-stored-items: false - # Make sure to keep enabled on 1.16+, otherwise netherite tools - # will mistakenly be set to max durability, due to some bug in paper. - skip-zero-durability: true - whitelisted-items: - - DIAMOND_CHESTPLATE - -###################### -# Dupe Preventions # -###################### -dupe-preventions: - # Prevent any possible dupes involving chested entities by making - # it impossible to put a chest on them. - # Only do this if you have reason to believe a dupe like that exists - # on your server. - prevent-chests-on-living-entities: false - # Closes open inventories of all entities that are in a chunk - # that will be unloaded. - close-entity-inventories-on-chunk-unload: false - # Prevents entities that can carry chests from using portals to - # block some common dupe tactics. - # CAUTION: Will remove chests and their contents from a chested - # entity if it touches a portal on Folia! - prevent-chested-living-entities-in-portals: false - # Patches a dupe that involves pushing a chestable entity - # with low hp into an end portal, duplicating its inventory - # content on death - prevent-end-portal-dupe: false - # Closes open inventories of entities that disappeared when the - # player riding it disconnects. - close-entity-inventories-on-player-disconnect: false - -################# -# Preventions # -################# -preventions: - withers: - disable-wither-spawning-at-spawn: - # Disables spawning withers near a configurable radius around - # spawn. Helps if players are generating endless amounts of withers - # to lag the server. - enable: false - inform-players: true - worlds: - world: 5000 - world_the_end: 5000 - world_nether: 5000 - remove-flying-wither-skulls: - # Removes wither skulls when the chunk gets unloaded. - # Use if you have a ton of them at spawn and they are causing lag. - on-chunk-unload: true - # Removes wither skulls when the chunk gets loaded. - # Use if you have a ton of them at spawn and they are causing lag. - on-chunk-load: true - periodically-remove-all-flying-skulls: - # Enable if a lot of wither skulls at spawn are causing lag. - enable: false - check-period-in-ticks: 80 - # Prevents wither skulls from being shot. - disable-withers-from-shooting-skulls: false - rate-limit-wither-skulls: - # This can help combat lag caused by a ton of wither skulls - # spawning but weakens withers. - enable: false - # Cooldown until another skull will be shot at a player - player-target-cooldown-in-ticks: 20 - # Cooldown until another skull can be shot at anything - # else other than a player. - other-target-cooldown-in-ticks: 40 - # Cooldown when wither has no target - no-target-cooldown-in-ticks: 100 - portals: - prevent-specific-types: - # Configure entities here that you suspect might be used in a dupe - # with portals. - # CAUTION: Will kill the entity on folia due to broken portal event. - # There is sadly no other efficient way. - enable: true - # Defaults prevent common lag methods. - entities: - - DROPPED_ITEM - - FIREWORK - - PRIMED_TNT - - THROWN_EXP_BOTTLE - - EXPERIENCE_ORB - - ARMOR_STAND - # Only enable if you must. Does not affect players. - prevent-all-entities-in-portals: false - prevent-destroying-end-portals: - enable: true - log: true - end: - bedrock-protection-radius-blocks: 8 - # Add block locations that should be protected as well. - # Format: ::: - # If you don't want to use this, just configure an empty list: - # pillar-blocks: [] - pillar-blocks: - - world_the_end:143:140:-50 - - world_the_end:112:90:-90 - prevent-portal-traps: - # Teleports a player back to the original location if they have been - # standing in a portal for too long. - enable: false - wait-time-until-tp-back-in-seconds: 10 - # Prevents a lag exploit. Might disable some chunk loader designs. - prevent-projectiles-in-portals: false - permanent-block-breaking: - by-placing-piston-on-retract: - enable: true - whitelisted-worlds: - - example_world_name - by-exploding-pistons: - enable: true - whitelisted-worlds: - - example_world_name - by-growing-structures: - # Prevents removal of permanent blocks by growing structures - # like mushrooms into them. - enable: true - prevent-map-reset-spam: - # Puts a cooldown on creating maps so players cant reset - # map arts that easily. - # Only needed on versions below 1.12 and lower. - # Bypass permission: aef.bypass.mapspam - enable: false - # Sends a message to players telling them how many maps - # they can create per time - notify-players: true - cooldown-time-in-minutes: 60 - max-amount-of-maps-per-time: 4 - prevent-ambient-fish-spawns: - # Prevent certain fish types from spawning in newer versions to combat lag. - enable: false - fish-types-to-prevent: - - COD - - SALMON - - PUFFERFISH - - TROPICAL_FISH - prevent-opped-players: - # Useful if you suspect a backdoor has happened. - enable: false - log: true - whitelisted-players: - - Notch - prevent-nether-roof: - # Prevent players from going above the nether roof. - enable: true - safely-teleport-players: true - anti-bed-trap: - # Resets a players bed respawn they die too many times within - # a certain timeframe. - enable: false - log: false - # Amount of times player can die until he is determined as bed-trapped. - max-deaths-per-time: 7 - # Time until death counter will be reset again - time-in-seconds: 5 - max-distance-from-bed: 6.0 - prevent-non-survival-players: - # Checks if player is in survival and if not, puts him back into survival. - # Useful if you had a backdoor incident. - enable: false - log: true - whitelisted-players: - - Notch - -############ -# Combat # -############ -combat: - anchor-aura-delay: - enable: false - # 1 tick = 50 ms - break-delay-millis: 0 - # 1 tick = 50 ms - place-delay-millis: 400 - # Can help with desync but recommended to leave off unless you have issues. - update-inventory-on-cancel: false - silent-swap-delay: - enable: false - # The delay in millis a player cant swap hotbar items after placing - # a block, clicking a block (for example to place a crystal) or - # damaging an entity. (50 ms = 1 tick) - min-swap-delay-millis: 40 - prevent-bow-bomb: - enable: false - # Fully pulled bow is ~9-10. 15 is default just to be safe. - max-bow-squared-velocity: 15 - portal-god-mode-patch: - # Prevents an exploit that allows players to stand in nether portals and not - # take damage indefinitely by just never sending a TeleportConfirm packet to - # the server. - # A similar method is used for the chorus tp exploit, which is not covered - # by this module. - enable: false - # If the player stays inside the nether portal for this time without teleporting, - # the portal will be broken, making the player inside vulnerable again. - # Nether portal teleports normally happen within ~3s after enter, so 5s (100ticks) - # should be a safe value. - break-portal-delay-ticks: 100 - crystal-aura: - piston-aura-delay: - # Rate-limits pistons that extend into crystals - enable: false - piston-extend-delay-in-ticks: 40 - regular-delay: - enable: false - # 1 tick = 50 ms - break-delay-millis: 200 - # 1 tick = 50 ms - place-delay-millis: 0 - # Can help with desync but recommended to leave off unless you have issues. - update-inventory-on-cancel: false - prevent-burrow: - enable: false - # 1.0 = Half a heart of damage every time you move. - damage-when-moving: 1.0 - teleport-above-block: true - # Prevent burrow even if there is a block above the block they - # are burrowing in. - # Please note this may allow creating an 'elevator', players will - # keep teleporting up until they hit air. - prevent-if-block-above-burrow: false - break-anvil-instead-of-teleport: true - # Needs to be enabled to prevent a bug where players are teleported - # above a slab when the slab is underwater. - allow-slabs-in-burrow: true - ignored-materials: - - BLACK_SHULKER_BOX - - BLUE_SHULKER_BOX - - BROWN_SHULKER_BOX - - CYAN_SHULKER_BOX - - GRAY_SHULKER_BOX - - GREEN_SHULKER_BOX - - LIGHT_BLUE_SHULKER_BOX - - SILVER_SHULKER_BOX - - LIME_SHULKER_BOX - - MAGENTA_SHULKER_BOX - - ORANGE_SHULKER_BOX - - PINK_SHULKER_BOX - - PURPLE_SHULKER_BOX - - RED_SHULKER_BOX - - PURPLE_SHULKER_BOX - - WHITE_SHULKER_BOX - - YELLOW_SHULKER_BOX - - AIR - - DIRT - - GRASS_PATH - - SAND - - GRAVEL - multi-task-patch: - enable: false - piston-push: - # Disables pistons from extending if it would push certain configured entities. - # This can be used to prevent players from pushing other players out of burrows, by - # configuring PLAYER, or to disable piston-crystal by adding ENDER_CRYSTAL to the list. - enable: false - piston-push-blocked-entities: - - PLAYER - bed-aura-delay: - enable: false - # 1 tick = 50 ms - break-delay-millis: 0 - # 1 tick = 50 ms - place-delay-millis: 250 - # Can help with desync but recommended to leave off unless you have issues. - update-inventory-on-cancel: false - -############# -# Bedrock # -############# -bedrock: - fill-in-bedrock: - overworld-floor: - periodically-check-and-fill: - # only checks loaded chunks - enable: false - check-period-in-seconds: 10 - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - fill-on-chunkload: - enable: false - # Recommended to leave off. Only useful if world generation is broken. - also-check-new-chunks: false - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - nether-ceiling: - periodically-check-and-fill: - # Only checks loaded chunks. - enable: false - check-period-in-seconds: 10 - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - fill-on-chunkload: - enable: false - # Recommended to leave off. Only useful if world generation is broken. - also-check-new-chunks: false - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - # Pauses the task during low tps to avoid adding to the lag. - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - nether-floor: - periodically-check-and-fill: - # Only checks loaded chunks. - enable: false - check-period-in-seconds: 10 - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - fill-on-chunkload: - enable: false - # Recommended to leave off. Only useful if world generation is broken. - also-check-new-chunks: false - # Uses the exact name of the world's folder in your server directory. - exempted-worlds: - - exampleworld - - exampleworld2 - pause-on-low-tps: true - # The TPS at which bedrock filling will pause to avoid adding to the lag. - pause-tps: 16.0 - prevent-going-below-bedrock-floor: - # Prevents players from going below the bedrock floor. - enable: true - # Eject player from the vehicle - eject-player: true - # Disables a player's elytra flight - stop-elytra: true - # Teleport player on top of that bedrock - teleport: true - # 1.0 = Half a heart of damage every time you move. Set 0 to disable - damage-when-moving: 8.0 - # Whether the bedrock hole should be filled or not - fill-bedrock-hole: true - exempted-worlds: - - world_the_end - - skyblock_world - filler-material: BEDROCK diff --git a/AnarchyExploitFixesLegacy/src/main/resources/plugin.yml b/AnarchyExploitFixesLegacy/src/main/resources/plugin.yml index 5b065a81e..c8c42e9a6 100755 --- a/AnarchyExploitFixesLegacy/src/main/resources/plugin.yml +++ b/AnarchyExploitFixesLegacy/src/main/resources/plugin.yml @@ -6,6 +6,7 @@ authors: [ xGinko, moo ] description: ${description} softdepend: - packetevents + - LuckPerms api-version: '1.13' folia-supported: false website: ${url} \ No newline at end of file diff --git a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts index a1b288030..ffbdd3f56 100755 --- a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts +++ b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.xginko" -version = "2.7.2" +version = "2.7.3" description = "Prevent many exploits that affect anarchy servers." var url: String? = "github.com/xGinko/AnarchyExploitFixes" @@ -43,10 +43,10 @@ repositories { } dependencies { - compileOnly("com.github.retrooper:packetevents-spigot:2.4.0") // PacketEvents to patch packet based exploits - api("com.github.cryptomorin:XSeries:11.2.0.1") // Crossversion entitytype and material support - api("com.github.thatsmusic99:ConfigurationMaster-API:v2.0.0-rc.1") // ConfigurationMaster for enhanced config management - api("de.tr7zw:item-nbt-api:2.13.2") // NBT API for cross version nbt tag handling + compileOnly("com.github.retrooper:packetevents-spigot:2.7.0") // PacketEvents to patch packet based exploits + api("com.github.cryptomorin:XSeries:13.0.0") // Crossversion entitytype and material support + api("com.github.thatsmusic99:ConfigurationMaster-API:v2.0.0-rc.3") // ConfigurationMaster for enhanced config management + api("de.tr7zw:item-nbt-api:2.14.1") // NBT API for cross version nbt tag handling api("org.bstats:bstats-bukkit:3.0.2") // Bukkit bStats api("org.apache.commons:commons-math3:3.6.1") // FastMath api("org.reflections:reflections:0.10.2") // Reflections diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 32b468dfc..037d6961c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,21 +5,17 @@ runpaperversion = "1.20.4" foliabundle = "1.20.4-R0.1-SNAPSHOT" [libraries] -paper = "io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT" folia = "dev.folia:folia-api:1.20.4-R0.1-SNAPSHOT" paper12 = "com.destroystokyo.paper:paper-api:1.12.2-R0.1-SNAPSHOT" -configmaster = "com.github.thatsmusic99:ConfigurationMaster-API:v2.0.0-rc.1" -bstats = "org.bstats:bstats-bukkit:3.0.2" caffeineJ17 = "com.github.ben-manes.caffeine:caffeine:3.1.8" caffeineJ8 = "com.github.ben-manes.caffeine:caffeine:2.9.3" hikaricp = "com.zaxxer:HikariCP:5.1.0" -xseries = "com.github.cryptomorin:XSeries:11.2.0.1" -reflections = "org.reflections:reflections:0.10.2" +luckperms = "net.luckperms:api:5.4" [plugins] -runpaper = { id = "xyz.jpenilla.run-paper", version = "2.3.0" } -shadow = { id = "io.github.goooler.shadow", version = "8.1.8" } -userdev = { id = "io.papermc.paperweight.userdev", version = "1.7.1" } -downgradeJava = { id = "xyz.wagyourtail.jvmdowngrader", version = "1.0.0" } +runpaper = { id = "xyz.jpenilla.run-paper", version = "2.3.1" } +shadow = { id = "com.gradleup.shadow", version = "8.3.5" } +userdev = { id = "io.papermc.paperweight.userdev", version = "1.7.7" } +downgradeJava = { id = "xyz.wagyourtail.jvmdowngrader", version = "1.2.1" } [bundles] diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index e046e9221..1943cd32d 100755 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -7,6 +7,7 @@ plugins { dependencies { compileOnly(libs.folia) compileOnly(libs.caffeineJ8) + compileOnly(libs.luckperms) paperweight.foliaDevBundle(libs.versions.foliabundle.get()) } diff --git a/shared/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CWCommandSendListener.java b/shared/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CWCommandSendListener.java index ea1805e16..529756583 100755 --- a/shared/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CWCommandSendListener.java +++ b/shared/src/main/java/me/xginko/aef/modules/chat/commandwhitelist/CWCommandSendListener.java @@ -1,6 +1,6 @@ package me.xginko.aef.modules.chat.commandwhitelist; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; diff --git a/shared/src/main/java/me/xginko/aef/modules/patches/commandsign/SignCommandListener.java b/shared/src/main/java/me/xginko/aef/modules/patches/commandsign/SignCommandListener.java index eef8d0697..0da3fb7e1 100644 --- a/shared/src/main/java/me/xginko/aef/modules/patches/commandsign/SignCommandListener.java +++ b/shared/src/main/java/me/xginko/aef/modules/patches/commandsign/SignCommandListener.java @@ -1,7 +1,6 @@ package me.xginko.aef.modules.patches.commandsign; -import io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent; -import me.xginko.aef.enums.AEFPermission; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -20,7 +19,7 @@ public class SignCommandListener implements Listener { } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onSignCommandPreprocess(PlayerSignCommandPreprocessEvent event) { + private void onSignCommandPreprocess(io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event) { if (!event.getPlayer().hasPermission(AEFPermission.BYPASS_PREVENTION_COMMANDSIGN.bukkit())) { event.setCancelled(true); } diff --git a/shared/src/main/java/me/xginko/aef/utils/BlockUtil.java b/shared/src/main/java/me/xginko/aef/utils/BlockUtil.java index 13056d28d..17adbd027 100644 --- a/shared/src/main/java/me/xginko/aef/utils/BlockUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/BlockUtil.java @@ -1,13 +1,17 @@ package me.xginko.aef.utils; +import de.tr7zw.changeme.nbtapi.NBT; +import de.tr7zw.changeme.nbtapi.iface.ReadableNBT; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.data.Waterlogged; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.EnumMap; import java.util.Map; -public class BlockUtil { +public final class BlockUtil { private static final boolean WATERLOGGED_AVAILABLE; @@ -20,9 +24,13 @@ public static boolean isWaterloggedAvailable() { } private static final Map IS_WATERLOGGABLE_CACHE = new EnumMap<>(Material.class); - public static boolean isWaterlogged(BlockState blockState) { + public static boolean isWaterlogged(@Nullable BlockState blockState) { return blockState != null && IS_WATERLOGGABLE_CACHE.computeIfAbsent(blockState.getType(), k -> blockState.getBlockData() instanceof Waterlogged) && ((Waterlogged) blockState.getBlockData()).isWaterlogged(); } + + public static String getNBTString(@NotNull BlockState blockState) { + return NBT.get(blockState, ReadableNBT::toString); + } } diff --git a/shared/src/main/java/me/xginko/aef/utils/CachingPermTool.java b/shared/src/main/java/me/xginko/aef/utils/CachingPermTool.java deleted file mode 100644 index 774cef847..000000000 --- a/shared/src/main/java/me/xginko/aef/utils/CachingPermTool.java +++ /dev/null @@ -1,62 +0,0 @@ -package me.xginko.aef.utils; - -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; -import me.xginko.aef.enums.AEFPermission; -import me.xginko.aef.utils.models.Disableable; -import org.bukkit.entity.HumanEntity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.time.Duration; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -public final class CachingPermTool implements Disableable, Listener { - - private static final Map> permissionCacheMap = new ConcurrentHashMap<>(); - private static final Duration cacheDuration = Duration.ofSeconds(5); - - CachingPermTool(JavaPlugin plugin) { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - public static CachingPermTool enable(JavaPlugin plugin) { - return new CachingPermTool(plugin); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - for (Map.Entry> entry : permissionCacheMap.entrySet()) - entry.getValue().cleanUp(); - permissionCacheMap.clear(); - } - - public static boolean hasPermission(AEFPermission permission, HumanEntity human) { - Cache permCache = permissionCacheMap.computeIfAbsent(human.getUniqueId(), - k -> Caffeine.newBuilder().expireAfterWrite(cacheDuration).build()); - Boolean hasPermission = permCache.getIfPresent(permission); - if (hasPermission == null) { - hasPermission = human.hasPermission(permission.bukkit()); - permCache.put(permission, hasPermission); - } - return hasPermission; - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onLeave(PlayerQuitEvent event) { - permissionCacheMap.remove(event.getPlayer().getUniqueId()); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onKick(PlayerKickEvent event) { - permissionCacheMap.remove(event.getPlayer().getUniqueId()); - } -} diff --git a/shared/src/main/java/me/xginko/aef/utils/ChunkUtil.java b/shared/src/main/java/me/xginko/aef/utils/ChunkUtil.java index 0e393cc61..8d0cc187f 100644 --- a/shared/src/main/java/me/xginko/aef/utils/ChunkUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/ChunkUtil.java @@ -5,15 +5,18 @@ import org.bukkit.Location; import org.bukkit.util.NumberConversions; -public class ChunkUtil { +public final class ChunkUtil { - private static final boolean SET_FORCE_LOADED_AVAILABLE, GET_INHABITED_TIME_AVAILABLE; + private static final boolean SET_FORCE_LOADED_AVAILABLE, GET_INHABITED_TIME_AVAILABLE, + IS_ENTITIES_LOADED_AVAILABLE; static { SET_FORCE_LOADED_AVAILABLE = Crafty.hasMethod(Chunk.class, "setForceLoaded", boolean.class); GET_INHABITED_TIME_AVAILABLE = Crafty.hasMethod(Chunk.class, "getInhabitedTime"); + IS_ENTITIES_LOADED_AVAILABLE + = Crafty.hasMethod(Chunk.class, "isEntitiesLoaded"); } public static boolean canSetChunksForceLoaded() { @@ -34,12 +37,21 @@ public static long getInhabitedTime(Chunk chunk) { return GET_INHABITED_TIME_AVAILABLE ? chunk.getInhabitedTime() : 0L; } + // If any chunk coord is outside 30 million blocks, paper will warn about dangerous chunk retrieval + public static boolean isRetrievalUnsafe(Chunk chunk) { + return chunk.getX() > 1875000 || chunk.getZ() > 1875000 || chunk.getX() < -1875000 || chunk.getZ() < -1875000; + } + + public static boolean isEntitiesLoaded(Chunk chunk) { + return IS_ENTITIES_LOADED_AVAILABLE ? chunk.isEntitiesLoaded() : chunk.isLoaded(); + } + public static void createBedrockLayer(Chunk chunk, int y) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { - if (chunk.getBlock(x, y, z).getType() != XMaterial.BEDROCK.parseMaterial()) { + if (chunk.getBlock(x, y, z).getType() != XMaterial.BEDROCK.get()) { // prevent physics to avoid loading nearby chunks which causes infinite chunk loading loops - chunk.getBlock(x, y, z).setType(XMaterial.BEDROCK.parseMaterial(), false); + chunk.getBlock(x, y, z).setType(XMaterial.BEDROCK.get(), false); } } } @@ -57,6 +69,6 @@ public static double getChunkDistanceSquared(Chunk chunk, Location location) { public static double getChunkDistanceSquared(Location location1, Location location2) { return NumberConversions.square((location1.getBlockX() >> 4) - (location2.getBlockX() >> 4)) + - NumberConversions.square((location1.getBlockX() >> 4) - (location2.getBlockZ() >> 4)); + NumberConversions.square((location1.getBlockZ() >> 4) - (location2.getBlockZ() >> 4)); } } diff --git a/shared/src/main/java/me/xginko/aef/utils/CommandUtil.java b/shared/src/main/java/me/xginko/aef/utils/CommandUtil.java index ab25dcd83..f6bf527c2 100755 --- a/shared/src/main/java/me/xginko/aef/utils/CommandUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/CommandUtil.java @@ -7,7 +7,7 @@ /** * Credits go to: YouHaveTrouble (https://github.com/YouHaveTrouble/CommandWhitelist) */ -public class CommandUtil { +public final class CommandUtil { public static String getCommandLabel(String cmd) { String[] parts = cmd.split(" "); diff --git a/shared/src/main/java/me/xginko/aef/utils/EntityUtil.java b/shared/src/main/java/me/xginko/aef/utils/EntityUtil.java index 687448f5a..851790f12 100644 --- a/shared/src/main/java/me/xginko/aef/utils/EntityUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/EntityUtil.java @@ -22,10 +22,9 @@ import java.util.Set; import java.util.stream.Collectors; -public class EntityUtil { +public final class EntityUtil { - private static final boolean MAP_SET_TRACKING_POS_AVAILABLE; - private static final boolean IS_SWIMMING_AVAILABLE; + public static final boolean MAP_SET_TRACKING_POS_AVAILABLE, IS_SWIMMING_AVAILABLE, IS_SET_PERSISTENT_AVAILABLE; static { MAP_SET_TRACKING_POS_AVAILABLE @@ -33,23 +32,28 @@ public class EntityUtil { && Crafty.hasMethod(MapView.class, "setTrackingPosition", boolean.class); IS_SWIMMING_AVAILABLE = Crafty.hasMethod(LivingEntity.class, "isSwimming", boolean.class); + IS_SET_PERSISTENT_AVAILABLE + = Crafty.hasMethod(Entity.class, "setPersistent", boolean.class); } - public static boolean canDisableMapPositionCursor() { - return MAP_SET_TRACKING_POS_AVAILABLE; + public static void setPersistent(Entity entity, boolean persistent) { + if (IS_SET_PERSISTENT_AVAILABLE) { + entity.setPersistent(persistent); + } } /** * Disables that a position cursor will be shown when the map is near its center. - * Check {@link EntityUtil#canDisableMapPositionCursor()} before calling this method. * * @param itemFrame the {@link ItemFrame} entity to disable the tracking status of */ public static void disableMapPositionCursor(@NotNull ItemFrame itemFrame) { + if (!MAP_SET_TRACKING_POS_AVAILABLE) return; + ItemStack itemInsideFrame = itemFrame.getItem(); if (itemInsideFrame == null) return; // Shouldn't be null but just in case - if (itemInsideFrame.getType() != XMaterial.MAP.parseMaterial() - && itemInsideFrame.getType() != XMaterial.FILLED_MAP.parseMaterial()) return; + if (itemInsideFrame.getType() != XMaterial.MAP.get() + && itemInsideFrame.getType() != XMaterial.FILLED_MAP.get()) return; if (!itemInsideFrame.hasItemMeta()) return; MapMeta mapMeta = (MapMeta) itemInsideFrame.getItemMeta(); diff --git a/shared/src/main/java/me/xginko/aef/utils/GenericUtil.java b/shared/src/main/java/me/xginko/aef/utils/GenericUtil.java new file mode 100644 index 000000000..9d5ff33f3 --- /dev/null +++ b/shared/src/main/java/me/xginko/aef/utils/GenericUtil.java @@ -0,0 +1,21 @@ +package me.xginko.aef.utils; + +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.Map; + +public final class GenericUtil { + + @SafeVarargs + public static Map mapOfEntries(Map.Entry... entries) { + Map map = new HashMap<>(); + for (Map.Entry entry : entries) { + map.put(entry.getKey(), entry.getValue()); + } + return map; + } + + public static Map.Entry mapEntry(K key, V value) { + return new AbstractMap.SimpleEntry<>(key, value); + } +} diff --git a/shared/src/main/java/me/xginko/aef/utils/ItemUtil.java b/shared/src/main/java/me/xginko/aef/utils/ItemUtil.java index 21cafb4ca..eab720aab 100644 --- a/shared/src/main/java/me/xginko/aef/utils/ItemUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/ItemUtil.java @@ -14,7 +14,7 @@ import java.nio.charset.StandardCharsets; -public class ItemUtil { +public final class ItemUtil { private static final boolean BUNDLES_SUPPPORTED, USE_MINIMSG_BOOKMETA; @@ -48,7 +48,7 @@ public class ItemUtil { } } - if (BUNDLES_SUPPPORTED && itemStack.getType() == XMaterial.BUNDLE.parseMaterial()) { + if (BUNDLES_SUPPPORTED && itemStack.getType() == XMaterial.BUNDLE.get()) { return ((BundleMeta) itemStack.getItemMeta()).getItems(); } diff --git a/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java b/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java index 89ac27ebb..3f59bea5d 100755 --- a/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java @@ -19,7 +19,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class MaterialUtil { +public final class MaterialUtil { public static final Set INVENTORY_HOLDERS = Arrays.stream(Material.values()) .filter(Material::isItem) // Prevents loading issues in 1.20.6+ @@ -32,76 +32,76 @@ public class MaterialUtil { public static final Set LECTERN_BOOKS = XTag.ITEMS_LECTERN_BOOKS.getValues().stream() .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set SIGNS = XTag.SIGNS.getValues().stream() .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set TRAPDOORS = XTag.TRAPDOORS.getValues().stream() .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set PRESSURE_PLATES = XTag.PRESSURE_PLATES.getValues().stream() .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set SHULKER_BOXES = XTag.SHULKER_BOXES.getValues().stream() .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set ANVILS = XTag.ANVIL.getValues().stream() .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set BEDS = XTag.BEDS.getValues().stream() .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set POTIONS = Arrays.stream(XMaterial.values()) .filter(xMaterial -> xMaterial.name().toUpperCase().contains("POTION")) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set PISTONS = Arrays.stream(XMaterial.values()) .filter(xMaterial -> xMaterial.name().toUpperCase().contains("PISTON")) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set SPAWN_EGGS = Arrays.stream(XMaterial.values()) .filter(xMaterial -> xMaterial.name().toUpperCase().endsWith("_SPAWN_EGG")) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set SLAB_LIKE = Stream.concat( Arrays.stream(XMaterial.values()).filter(xMaterial -> xMaterial.name().toUpperCase().endsWith("_SLAB")), Stream.of(XMaterial.SCULK_SENSOR, XMaterial.CALIBRATED_SCULK_SENSOR, XMaterial.SCULK_SHRIEKER)) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set PLAYER_HEADS = Stream.of( XMaterial.PLAYER_HEAD, XMaterial.PLAYER_WALL_HEAD) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set REDSTONE = Stream.of( XMaterial.REDSTONE, XMaterial.REDSTONE_WIRE) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); // Blocks that the player gets lowered into slightly when walking on them @@ -110,7 +110,7 @@ public class MaterialUtil { XMaterial.FARMLAND, XMaterial.MUD) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set SOLID_INDESTRUCTIBLES = Stream.of( @@ -122,11 +122,11 @@ public class MaterialUtil { XMaterial.BARRIER, XMaterial.COMMAND_BLOCK) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static final Set INDESTRUCTIBLES = Stream.concat(SOLID_INDESTRUCTIBLES.stream(), - Stream.of(XMaterial.END_PORTAL.parseMaterial())) + Stream.of(XMaterial.END_PORTAL.get())) .filter(Objects::nonNull) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); @@ -141,11 +141,16 @@ public class MaterialUtil { XMaterial.TADPOLE_BUCKET, XMaterial.POWDER_SNOW_BUCKET) .filter(XMaterial::isSupported) - .map(XMaterial::parseMaterial) + .map(XMaterial::get) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); + + public static final Set AIR = XTag.AIR.getValues().stream() + .filter(XMaterial::isSupported) + .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); public static boolean isElytra(@Nullable ItemStack itemStack) { - return itemStack != null && itemStack.getType() == XMaterial.ELYTRA.parseMaterial(); + return itemStack != null && itemStack.getType() == XMaterial.ELYTRA.get(); } @SuppressWarnings("deprecation") @@ -170,8 +175,9 @@ public static boolean isPlayerHead(ItemStack itemStack) { return true; if (itemStack.getItemMeta() instanceof BlockStateMeta) { BlockStateMeta blockStateMeta = (BlockStateMeta) itemStack.getItemMeta(); - if (blockStateMeta.hasBlockState() && blockStateMeta.getBlockState() instanceof Skull) + if (blockStateMeta.hasBlockState() && blockStateMeta.getBlockState() instanceof Skull) { return ((Skull) blockStateMeta.getBlockState()).getSkullType() == SkullType.PLAYER; + } } return false; } diff --git a/shared/src/main/java/me/xginko/aef/utils/PlatformUtil.java b/shared/src/main/java/me/xginko/aef/utils/PlatformUtil.java index 3f364bdba..eb2bf9511 100644 --- a/shared/src/main/java/me/xginko/aef/utils/PlatformUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/PlatformUtil.java @@ -7,19 +7,22 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class PlatformUtil { +public final class PlatformUtil { private static int minecraftVersion, minecraftPatchVersion, minecraftPreReleaseVersion, minecraftReleaseCandidateVersion; - private static boolean isServerPaper, isServerFolia, isServerPurpur; + private static boolean isServerPaper, isServerFolia, isServerPurpur, isServerSpigot; public static void load() { isServerPurpur - = Crafty.hasClass("org.purpurmc.purpur.PurpurConfig"); + = Crafty.hasClass("org.purpurmc.purpur.PurpurConfig") + || Crafty.hasClass("net.pl3x.purpur.PurpurConfig"); isServerPaper = Crafty.hasClass("com.destroystokyo.paper.PaperConfig") || Crafty.hasClass("io.papermc.paper.configuration.Configuration"); isServerFolia = Crafty.hasClass("io.papermc.paper.threadedregions.RegionizedServer"); + isServerSpigot + = Crafty.hasClass("org.spigotmc.SpigotConfig"); // From PaperLib Matcher matcher = Pattern.compile("(?i)\\(MC: (\\d)\\.(\\d+)\\.?(\\d+?)?(?: (Pre-Release|Release Candidate) )?(\\d)?\\)") @@ -77,4 +80,31 @@ public static int getMinecraftPreReleaseVersion() { public static int getMinecraftReleaseCandidateVersion() { return minecraftReleaseCandidateVersion; } + + public static ServerType getServerType() { + if (isServerFolia) return ServerType.FOLIA; + if (isServerPurpur) return ServerType.PURPUR; + if (isServerPaper) return ServerType.PAPER; + if (isServerSpigot) return ServerType.SPIGOT; + return ServerType.UNKNOWN; + } + + public enum ServerType { + + PAPER("Paper"), + PURPUR("Purpur"), + FOLIA("Folia"), + SPIGOT("Spigot"), + UNKNOWN("Unknown"); + + private final String niceName; + + ServerType(String niceName) { + this.niceName = niceName; + } + + public String niceName() { + return niceName; + } + } } diff --git a/shared/src/main/java/me/xginko/aef/enums/IllegalHandling.java b/shared/src/main/java/me/xginko/aef/utils/enums/IllegalHandling.java similarity index 92% rename from shared/src/main/java/me/xginko/aef/enums/IllegalHandling.java rename to shared/src/main/java/me/xginko/aef/utils/enums/IllegalHandling.java index c2eb75ccc..afc7f8ddf 100644 --- a/shared/src/main/java/me/xginko/aef/enums/IllegalHandling.java +++ b/shared/src/main/java/me/xginko/aef/utils/enums/IllegalHandling.java @@ -1,4 +1,4 @@ -package me.xginko.aef.enums; +package me.xginko.aef.utils.enums; public enum IllegalHandling { diff --git a/shared/src/main/java/me/xginko/aef/enums/ItemLegality.java b/shared/src/main/java/me/xginko/aef/utils/enums/ItemLegality.java similarity index 68% rename from shared/src/main/java/me/xginko/aef/enums/ItemLegality.java rename to shared/src/main/java/me/xginko/aef/utils/enums/ItemLegality.java index 989b39a8b..19eff7fbb 100644 --- a/shared/src/main/java/me/xginko/aef/enums/ItemLegality.java +++ b/shared/src/main/java/me/xginko/aef/utils/enums/ItemLegality.java @@ -1,4 +1,4 @@ -package me.xginko.aef.enums; +package me.xginko.aef.utils.enums; public enum ItemLegality { LEGAL, diff --git a/shared/src/main/java/me/xginko/aef/utils/enums/TriState.java b/shared/src/main/java/me/xginko/aef/utils/enums/TriState.java new file mode 100644 index 000000000..9fefa5bdf --- /dev/null +++ b/shared/src/main/java/me/xginko/aef/utils/enums/TriState.java @@ -0,0 +1,28 @@ +package me.xginko.aef.utils.enums; + +import org.checkerframework.checker.nullness.qual.NonNull; + +public enum TriState { + + UNDEFINED(false), + FALSE(false), + TRUE(true); + + private final boolean booleanValue; + + TriState(boolean booleanValue) { + this.booleanValue = booleanValue; + } + + public boolean toBoolean() { + return this.booleanValue; + } + + public static @NonNull TriState of(boolean val) { + return val ? TRUE : FALSE; + } + + public static @NonNull TriState of(Boolean val) { + return val == null ? UNDEFINED : (val ? TRUE : FALSE); + } +} diff --git a/shared/src/main/java/me/xginko/aef/utils/models/ExpiringSet.java b/shared/src/main/java/me/xginko/aef/utils/models/ExpiringSet.java index 48cb24829..9aa308514 100644 --- a/shared/src/main/java/me/xginko/aef/utils/models/ExpiringSet.java +++ b/shared/src/main/java/me/xginko/aef/utils/models/ExpiringSet.java @@ -11,6 +11,9 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +/** + * {@inheritDoc} + */ public final class ExpiringSet extends AbstractSet implements Set { private final Cache cache; @@ -24,214 +27,53 @@ public ExpiringSet(Duration duration) { this.cache = Caffeine.newBuilder().expireAfterWrite(duration).build(); } - /** - * Returns the number of elements in this set (its cardinality). If this - * set contains more than {@code Integer.MAX_VALUE} elements, returns - * {@code Integer.MAX_VALUE}. - * - * @return the number of elements in this set (its cardinality) - */ @Override public int size() { return this.cache.asMap().size(); } - /** - * Returns {@code true} if this set contains no elements. - * - * @return {@code true} if this set contains no elements - */ @Override public boolean isEmpty() { return this.cache.asMap().isEmpty(); } - /** - * Returns {@code true} if this set contains the specified element. - * More formally, returns {@code true} if and only if this set - * contains an element {@code e} such that - * {@code Objects.equals(o, e)}. - * - * @param item element whose presence in this set is to be tested - * @return {@code true} if this set contains the specified element - * @throws ClassCastException if the type of the specified element - * is incompatible with this set - * (optional) - * @throws NullPointerException if the specified element is null and this - * set does not permit null elements - * (optional) - */ @Override public boolean contains(Object item) { return this.cache.getIfPresent((E) item) != null; } - /** - * Returns an iterator over the elements in this set. The elements are - * returned in no particular order (unless this set is an instance of some - * class that provides a guarantee). - * - * @return an iterator over the elements in this set - */ @Override public @NotNull Iterator iterator() { return this.cache.asMap().keySet().iterator(); } - /** - * Returns an array containing all of the elements in this set. - * If this set makes any guarantees as to what order its elements - * are returned by its iterator, this method must return the - * elements in the same order. - * - *

The returned array will be "safe" in that no references to it - * are maintained by this set. (In other words, this method must - * allocate a new array even if this set is backed by an array). - * The caller is thus free to modify the returned array. - * - *

This method acts as bridge between array-based and collection-based - * APIs. - * - * @return an array containing all the elements in this set - */ @Override public @NotNull Object @NotNull [] toArray() { return this.cache.asMap().keySet().toArray(); } - /** - * Returns an array containing all of the elements in this set; the - * runtime type of the returned array is that of the specified array. - * If the set fits in the specified array, it is returned therein. - * Otherwise, a new array is allocated with the runtime type of the - * specified array and the size of this set. - * - *

If this set fits in the specified array with room to spare - * (i.e., the array has more elements than this set), the element in - * the array immediately following the end of the set is set to - * {@code null}. (This is useful in determining the length of this - * set only if the caller knows that this set does not contain - * any null elements.) - * - *

If this set makes any guarantees as to what order its elements - * are returned by its iterator, this method must return the elements - * in the same order. - * - *

Like the {@link #toArray()} method, this method acts as bridge between - * array-based and collection-based APIs. Further, this method allows - * precise control over the runtime type of the output array, and may, - * under certain circumstances, be used to save allocation costs. - * - *

Suppose {@code x} is a set known to contain only strings. - * The following code can be used to dump the set into a newly allocated - * array of {@code String}: - * - *

-     *     String[] y = x.toArray(new String[0]);
- *

- * Note that {@code toArray(new Object[0])} is identical in function to - * {@code toArray()}. - * - * @param a the array into which the elements of this set are to be - * stored, if it is big enough; otherwise, a new array of the same - * runtime type is allocated for this purpose. - * @return an array containing all the elements in this set - * @throws ArrayStoreException if the runtime type of the specified array - * is not a supertype of the runtime type of every element in this - * set - * @throws NullPointerException if the specified array is null - */ @Override public @NotNull T @NotNull [] toArray(@NotNull T @NotNull [] a) { return this.cache.asMap().keySet().toArray(a); } - /** - * Adds the specified element to this set if it is not already present - * (optional operation). More formally, adds the specified element - * {@code e} to this set if the set contains no element {@code e2} - * such that - * {@code Objects.equals(e, e2)}. - * If this set already contains the element, the call leaves the set - * unchanged and returns {@code false}. In combination with the - * restriction on constructors, this ensures that sets never contain - * duplicate elements. - * - *

The stipulation above does not imply that sets must accept all - * elements; sets may refuse to add any particular element, including - * {@code null}, and throw an exception, as described in the - * specification for {@link Collection#add Collection.add}. - * Individual set implementations should clearly document any - * restrictions on the elements that they may contain. - * - * @param item element to be added to this set - * @return {@code true} if this set did not already contain the specified - * element - * @throws UnsupportedOperationException if the {@code add} operation - * is not supported by this set - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this set - * @throws NullPointerException if the specified element is null and this - * set does not permit null elements - * @throws IllegalArgumentException if some property of the specified element - * prevents it from being added to this set - */ + @Override public boolean add(E item) { boolean containedBefore = this.contains(item); this.cache.put(item, PRESENT); return !containedBefore; } - /** - * Removes the specified element from this set if it is present - * (optional operation). More formally, removes an element {@code e} - * such that - * {@code Objects.equals(o, e)}, if - * this set contains such an element. Returns {@code true} if this set - * contained the element (or equivalently, if this set changed as a - * result of the call). (This set will not contain the element once the - * call returns.) - * - * @param o object to be removed from this set, if present - * @return {@code true} if this set contained the specified element - * @throws ClassCastException if the type of the specified element - * is incompatible with this set - * (optional) - * @throws NullPointerException if the specified element is null and this - * set does not permit null elements - * (optional) - * @throws UnsupportedOperationException if the {@code remove} operation - * is not supported by this set - */ @Override public boolean remove(Object o) { - boolean present = this.contains(o); - if (present) this.cache.invalidate((E) o); - return present; + boolean containedBefore = this.contains(o); + this.cache.invalidate((E) o); + return containedBefore; } - /** - * Returns {@code true} if this set contains all of the elements of the - * specified collection. If the specified collection is also a set, this - * method returns {@code true} if it is a subset of this set. - * - * @param c collection to be checked for containment in this set - * @return {@code true} if this set contains all of the elements of the - * specified collection - * @throws ClassCastException if the types of one or more elements - * in the specified collection are incompatible with this - * set - * (optional) - * @throws NullPointerException if the specified collection contains one - * or more null elements and this set does not permit null - * elements - * (optional), - * or if the specified collection is null - * @see #contains(Object) - */ @Override - public boolean containsAll(@NotNull Collection c) { - for (Object o : c) { + public boolean containsAll(@NotNull Collection collection) { + for (Object o : collection) { if (!this.contains(o)) { return false; } @@ -239,31 +81,10 @@ public boolean containsAll(@NotNull Collection c) { return true; } - /** - * Adds all of the elements in the specified collection to this set if - * they're not already present (optional operation). If the specified - * collection is also a set, the {@code addAll} operation effectively - * modifies this set so that its value is the union of the two - * sets. The behavior of this operation is undefined if the specified - * collection is modified while the operation is in progress. - * - * @param c collection containing elements to be added to this set - * @return {@code true} if this set changed as a result of the call - * @throws UnsupportedOperationException if the {@code addAll} operation - * is not supported by this set - * @throws ClassCastException if the class of an element of the - * specified collection prevents it from being added to this set - * @throws NullPointerException if the specified collection contains one - * or more null elements and this set does not permit null - * elements, or if the specified collection is null - * @throws IllegalArgumentException if some property of an element of the - * specified collection prevents it from being added to this set - * @see #add(Object) - */ @Override - public boolean addAll(@NotNull Collection c) { + public boolean addAll(@NotNull Collection collection) { boolean changed = false; - for (E o : c) { + for (E o : collection) { if (this.add(o)) { changed = true; } @@ -271,61 +92,19 @@ public boolean addAll(@NotNull Collection c) { return changed; } - /** - * Retains only the elements in this set that are contained in the - * specified collection (optional operation). In other words, removes - * from this set all of its elements that are not contained in the - * specified collection. If the specified collection is also a set, this - * operation effectively modifies this set so that its value is the - * intersection of the two sets. - * - * @param c collection containing elements to be retained in this set - * @return {@code true} if this set changed as a result of the call - * @throws UnsupportedOperationException if the {@code retainAll} operation - * is not supported by this set - * @throws ClassCastException if the class of an element of this set - * is incompatible with the specified collection - * (optional) - * @throws NullPointerException if this set contains a null element and the - * specified collection does not permit null elements - * (optional), - * or if the specified collection is null - * @see #remove(Object) - */ @Override - public boolean retainAll(@NotNull Collection c) { + public boolean retainAll(@NotNull Collection collection) { boolean changed = false; for (E e : this.cache.asMap().keySet()) { - if (!c.contains(e) && this.remove(e)) { + if (!collection.contains(e) && this.remove(e)) { changed = true; } } return changed; } - /** - * Removes from this set all of its elements that are contained in the - * specified collection (optional operation). If the specified - * collection is also a set, this operation effectively modifies this - * set so that its value is the asymmetric set difference of - * the two sets. - * - * @param c collection containing elements to be removed from this set - * @return {@code true} if this set changed as a result of the call - * @throws UnsupportedOperationException if the {@code removeAll} operation - * is not supported by this set - * @throws ClassCastException if the class of an element of this set - * is incompatible with the specified collection - * (optional) - * @throws NullPointerException if this set contains a null element and the - * specified collection does not permit null elements - * (optional), - * or if the specified collection is null - * @see #remove(Object) - * @see #contains(Object) - */ @Override - public boolean removeAll(@NotNull Collection c) { + public boolean removeAll(@NotNull Collection collection) { boolean changed = false; for (E e : this.cache.asMap().keySet()) { if (this.remove(e)) { @@ -335,15 +114,12 @@ public boolean removeAll(@NotNull Collection c) { return changed; } - /** - * Removes all of the elements from this set (optional operation). - * The set will be empty after this call returns. - * - * @throws UnsupportedOperationException if the {@code clear} method - * is not supported by this set - */ @Override public void clear() { this.cache.invalidateAll(); } + + public void cleanUp() { + this.cache.cleanUp(); + } } \ No newline at end of file diff --git a/shared/src/main/java/me/xginko/aef/utils/models/Lazy.java b/shared/src/main/java/me/xginko/aef/utils/models/Lazy.java new file mode 100644 index 000000000..6f33a2c4e --- /dev/null +++ b/shared/src/main/java/me/xginko/aef/utils/models/Lazy.java @@ -0,0 +1,35 @@ +package me.xginko.aef.utils.models; + +import java.util.Objects; +import java.util.function.Supplier; + +public class Lazy implements Supplier { + + private final Supplier supplier; + private E value; + + private Lazy(Supplier supplier) { + this.supplier = supplier; + } + + public static Lazy of(Supplier supplier) { + Objects.requireNonNull(supplier, "Can't create lazy if supplier is null!"); + return new Lazy<>(supplier); + } + + public boolean isEmpty() { + return this.value == null; + } + + public void clear() { + this.value = null; + } + + @Override + public E get() { + if (this.isEmpty()) { + this.value = this.supplier.get(); + } + return this.value; + } +} diff --git a/shared/src/main/java/me/xginko/aef/enums/AEFPermission.java b/shared/src/main/java/me/xginko/aef/utils/permissions/AEFPermission.java similarity index 88% rename from shared/src/main/java/me/xginko/aef/enums/AEFPermission.java rename to shared/src/main/java/me/xginko/aef/utils/permissions/AEFPermission.java index b6be7976a..3f6353fad 100644 --- a/shared/src/main/java/me/xginko/aef/enums/AEFPermission.java +++ b/shared/src/main/java/me/xginko/aef/utils/permissions/AEFPermission.java @@ -1,4 +1,4 @@ -package me.xginko.aef.enums; +package me.xginko.aef.utils.permissions; import org.bukkit.Bukkit; import org.bukkit.permissions.Permission; @@ -45,35 +45,37 @@ public enum AEFPermission { CMD_SAY("cmd.say", "Broadcast a message using your own prefix and format", PermissionDefault.OP), CMD_HELP("cmd.help", "Show a command overview for players", PermissionDefault.TRUE); - - private final String permString; - private final Permission bukkitPerm; + private final Permission permission; AEFPermission(String perm, String description, PermissionDefault def) { - this.permString = "aef." + perm; - this.bukkitPerm = new Permission(permString, description, def); + this.permission = new Permission("aef." + perm, description, def); } - public String string() { - return permString; + public String node() { + return permission.getName(); } public Permission bukkit() { - return bukkitPerm; + return permission; } - public static void registerPermissions() { + public static void registerAll() { for (AEFPermission aefPermission : values()) { try { Bukkit.getPluginManager().addPermission(aefPermission.bukkit()); } catch (IllegalArgumentException e) { // If a permission is already defined with the given name, choose more specific name Bukkit.getPluginManager().addPermission(new Permission( - "xginko."+aefPermission.string(), + "xginko."+aefPermission.node(), aefPermission.bukkit().getDescription(), - aefPermission.bukkit().getDefault() - )); + aefPermission.bukkit().getDefault())); } } } + + public static void unregisterAll() { + for (AEFPermission aefPermission : values()) { + Bukkit.getPluginManager().removePermission(aefPermission.bukkit()); + } + } } diff --git a/shared/src/main/java/me/xginko/aef/utils/permissions/BukkitPermissionHandler.java b/shared/src/main/java/me/xginko/aef/utils/permissions/BukkitPermissionHandler.java new file mode 100644 index 000000000..a0a8e4b51 --- /dev/null +++ b/shared/src/main/java/me/xginko/aef/utils/permissions/BukkitPermissionHandler.java @@ -0,0 +1,85 @@ +package me.xginko.aef.utils.permissions; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import me.xginko.aef.utils.enums.TriState; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.permissions.Permissible; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.java.JavaPlugin; + +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public final class BukkitPermissionHandler implements PermissionHandler, Listener { + + private final Map> permissionCacheMap; + private final Duration permissionCacheDuration; + + BukkitPermissionHandler(JavaPlugin plugin) { + permissionCacheDuration = Duration.ofSeconds(5); + permissionCacheMap = new ConcurrentHashMap<>(Math.min(8, plugin.getServer().getOnlinePlayers().size())); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + for (Map.Entry> entry : permissionCacheMap.entrySet()) { + flushCache(entry.getKey()); + } + } + + @Override + public TriState permissionValue(Permissible permissible, String permission) { + Cache permCache = permissionCacheMap.computeIfAbsent(permissible, sender -> + Caffeine.newBuilder().expireAfterWrite(permissionCacheDuration).build()); + TriState value = permCache.getIfPresent(permission); + if (value == null) { + value = permissible.isPermissionSet(permission) ? TriState.of(permissible.hasPermission(permission)) : TriState.UNDEFINED; + permCache.put(permission, value); + } + return value; + } + + @Override + public void setPermission(Permissible permissible, String permission, TriState state) { + for (PermissionAttachmentInfo attachmentInfo : permissible.getEffectivePermissions()) { + if (attachmentInfo.getAttachment() == null) { + continue; + } + + if (attachmentInfo.getPermission().equals(permission)) { + if (state == TriState.UNDEFINED) { + permissible.removeAttachment(attachmentInfo.getAttachment()); + } else { + permissible.addAttachment(attachmentInfo.getAttachment().getPlugin(), permission, state.toBoolean()); + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onPlayerQuit(PlayerQuitEvent event) { + flushCache(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onPlayerKick(PlayerKickEvent event) { + flushCache(event.getPlayer()); + } + + private void flushCache(Permissible permissible) { + if (permissionCacheMap.containsKey(permissible)) { + permissionCacheMap.get(permissible).invalidateAll(); + permissionCacheMap.get(permissible).cleanUp(); + permissionCacheMap.remove(permissible); + } + } +} diff --git a/shared/src/main/java/me/xginko/aef/utils/permissions/LuckPermsPermissionHandler.java b/shared/src/main/java/me/xginko/aef/utils/permissions/LuckPermsPermissionHandler.java new file mode 100644 index 000000000..362084880 --- /dev/null +++ b/shared/src/main/java/me/xginko/aef/utils/permissions/LuckPermsPermissionHandler.java @@ -0,0 +1,51 @@ +package me.xginko.aef.utils.permissions; + +import me.xginko.aef.utils.enums.TriState; +import net.luckperms.api.LuckPerms; +import net.luckperms.api.model.user.User; +import net.luckperms.api.node.Node; +import net.luckperms.api.util.Tristate; +import org.bukkit.entity.Player; +import org.bukkit.permissions.Permissible; +import org.bukkit.plugin.java.JavaPlugin; + +public final class LuckPermsPermissionHandler implements PermissionHandler { + + private final LuckPerms luckPerms; + private final BukkitPermissionHandler bukkitPermissionHandler; + + LuckPermsPermissionHandler(JavaPlugin plugin) { + luckPerms = plugin.getServer().getServicesManager().getRegistration(LuckPerms.class).getProvider(); + bukkitPermissionHandler = new BukkitPermissionHandler(plugin); // We use this one only for non-players + } + + @Override + public TriState permissionValue(Permissible permissible, String permission) { + if (permissible instanceof Player) { + Tristate permState = luckPerms.getPlayerAdapter(Player.class).getUser((Player) permissible) + .getCachedData().getPermissionData().checkPermission(permission); + if (permState == Tristate.TRUE) + return TriState.TRUE; + if (permState == Tristate.FALSE) + return TriState.FALSE; + return TriState.UNDEFINED; + } else { + return bukkitPermissionHandler.permissionValue(permissible, permission); + } + } + + @Override + public void setPermission(Permissible permissible, String permission, TriState state) { + if (permissible instanceof Player) { + User luckPermsUser = luckPerms.getPlayerAdapter(Player.class).getUser((Player) permissible); + if (state == TriState.UNDEFINED) { + luckPermsUser.data().remove(Node.builder(permission).build()); + } else { + luckPermsUser.data().add(Node.builder(permission).value(state.toBoolean()).build()); + } + luckPerms.getUserManager().saveUser(luckPermsUser); + } else { + bukkitPermissionHandler.setPermission(permissible, permission, state); + } + } +} diff --git a/shared/src/main/java/me/xginko/aef/utils/permissions/PermissionHandler.java b/shared/src/main/java/me/xginko/aef/utils/permissions/PermissionHandler.java new file mode 100644 index 000000000..02f55105e --- /dev/null +++ b/shared/src/main/java/me/xginko/aef/utils/permissions/PermissionHandler.java @@ -0,0 +1,26 @@ +package me.xginko.aef.utils.permissions; + +import me.xginko.aef.utils.Crafty; +import me.xginko.aef.utils.enums.TriState; +import me.xginko.aef.utils.models.Disableable; +import org.bukkit.permissions.Permissible; +import org.bukkit.plugin.java.JavaPlugin; + +public interface PermissionHandler extends Disableable { + + static PermissionHandler create(JavaPlugin plugin) { + if (Crafty.hasClass("net.luckperms.api.model.user.User") + && Crafty.hasClass("net.luckperms.api.node.Node") + && Crafty.hasClass("net.luckperms.api.util.Tristate") + && Crafty.hasClass("net.luckperms.api.LuckPerms")) { + return new LuckPermsPermissionHandler(plugin); + } + + return new BukkitPermissionHandler(plugin); + } + + default void disable() {} + TriState permissionValue(Permissible permissible, String permission); + void setPermission(Permissible permissible, String permission, TriState state); + +} diff --git a/shared/src/main/java/me/xginko/aef/utils/tickdata/SpigotReflection.java b/shared/src/main/java/me/xginko/aef/utils/tickdata/SpigotReflection.java index 99e25c6bb..0b6f84c38 100644 --- a/shared/src/main/java/me/xginko/aef/utils/tickdata/SpigotReflection.java +++ b/shared/src/main/java/me/xginko/aef/utils/tickdata/SpigotReflection.java @@ -33,8 +33,6 @@ import java.util.Arrays; import java.util.Objects; -import static me.xginko.aef.utils.Crafty.needNMSClassOrElse; - public final class SpigotReflection { private static SpigotReflection instance; @@ -44,7 +42,7 @@ public final class SpigotReflection { public static SpigotReflection getInstance() { if (instance == null) { - MinecraftServer_class = needNMSClassOrElse("MinecraftServer", "net.minecraft.server.MinecraftServer"); + MinecraftServer_class = Crafty.needNMSClassOrElse("MinecraftServer", "net.minecraft.server.MinecraftServer"); MinecraftServer_getServer_method = needStaticMethod(MinecraftServer_class, "getServer", MinecraftServer_class); MinecraftServer_recentTps_field = needField(MinecraftServer_class, "recentTps"); // Spigot added field MinecraftServer_recentTickTimes_field = tickTimesField();