Skip to content

Commit

Permalink
2.7.2 release (#233)
Browse files Browse the repository at this point in the history
- Added 1.21.1 compatibility (#232)
- Made map-cursor-lag-patch work on 1.12.2
- Replaced low-tps-physics modules with regional-activity modules. Any sort of activity that has the potential to lag or kill the server when happening at high frequencies can now be individually managed and configured. The base concept for this was suggested by @xKumorio (3b3t.org): Any time an activity is happening for the first time, the plugin will check in a radius around it for more activity of the same kind. If it exceeds a certain count within the configured timeframe, all activity in that radius (region) will be cancelled.
The only catch: Config defaults are pretty rough and will most likely need individual adjustments. Tests with a variety of lagmachine designs were pretty promising though. I would very much recommend to check out the entire `lag-preventions.regional-activity` section.
- Added a module against lag generated by forcing the server to send large ItemStacks. (Ex. fill chest with books, spam open chest). This is especially a problem with older game versions. Previous modules that were basically a worse attempt at fixing this issue have been removed in favor of this one. Basically works like an anti-spam that starts taking action once the player is exceeding a certain byte-size of requested data within a timeframe. Players will first be rate-limited and if they keep requesting data, locked out from requesting more for a configurable time.
- Replaced all deprecated NBT-API calls with the new ones. This makes AEF handling NBT more reliable.
- Added an illegal item module against illegal potion effects
- Added an illegal item module against illegal item attributes
- Fully reworked configurations for Crystal Aura, Anchor Aura and Bed Aura: You can now set place and break cooldowns per Hand on the Folia jar!
- Added a patch against MultiTask
- Rewrote the patch against SilentSwitch
- Improved the burrow patch slightly for more configurability
- Added a patch against PortalGodMode (#157)
- Improved compatibility with lower game versions by using reflections for TPS and MSPT. This also improved compatibility with unsupported older versions.
- Improved world height configuration and detection for Legacy users
- Fixed AEF being unable to detect player respawns on Folia
- Code optimizations and performance improvements

(cherry picked from commit d20da6e)
  • Loading branch information
xGinko committed Jan 4, 2025
1 parent eb71b59 commit 1f13acb
Show file tree
Hide file tree
Showing 55 changed files with 5,004 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public void enable() {
return subCommand.tabComplete(sender, alias, args);
}
}

return tabCompletes.stream().filter(cmd -> cmd.startsWith(args[0])).toList();
}

return Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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<AEFListener> 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);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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<UUID> 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class ElytraHelper extends AEFModule implements Runnable, PacketListener,
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");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
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<Material> 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<String> 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);
}
}
}
Loading

0 comments on commit 1f13acb

Please sign in to comment.