Compare commits

...

2 Commits

Author SHA1 Message Date
Helvetica Volubi 43036f971c feat: update Entity tick and removal limiter 2026-07-30 00:58:37 +08:00
Helvetica Volubi 25ce58c40d fix: fix folia nether portal ticket placement 2026-07-28 21:23:43 +08:00
5 changed files with 123 additions and 76 deletions
@@ -53,3 +53,15 @@ index c4d9d890db784d376b876d70f0468df6edb75168..0641b98ef3298eb682ceae83f60b730f
} finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ENTITY_TICK); } // Folia - profiler
if (this.paperConfig().unsupportedSettings.ticking.blockEntities) { // Paper - option to disable ticking
profiler.popPush("blockEntities");
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
index 6efaa78faca15c7a48bdffb24480d1bac29f3ba8..31619890f1bd4f458b6f9a31fac8cefaafe09e8e 100644
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
@@ -73,6 +73,7 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
private final float spawnDimensionsScale;
private final FeatureFlagSet requiredFeatures;
private final boolean allowedInPeaceful;
+ public volatile dev.kaiijumc.kaiiju.KaiijuEntityLimits.EntityLimit entityLimit;
public static Identifier getKey(final EntityType<?> type) {
return BuiltInRegistries.ENTITY_TYPE.getKey(type);
@@ -80,10 +80,10 @@ index 43e07a3c98e80f874f55411beac39e215ffdc3cf..cddf44f5da5cba5603dcff4913b4658d
+ // Lophine end - Add config to enable raytracing tracker
}
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
index 6efaa78faca15c7a48bdffb24480d1bac29f3ba8..8a328a41673a3d720f0b1a5de8ce049e360fac1b 100644
index 31619890f1bd4f458b6f9a31fac8cefaafe09e8e..50643bd0b546a1ff70031ea39e2610f219ef8a79 100644
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
@@ -84,6 +84,11 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
@@ -85,6 +85,11 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
public final int passengerTickTimerId;
public final int passengerInactiveTickTimerId;
// Folia end - profiler
@@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 28 Jul 2026 20:40:01 +0800
Subject: [PATCH] Anonymous Object: Fix folia nether portal ticket placement
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/util/BlockUtil.java b/net/minecraft/util/BlockUtil.java
index ea93ac07ec6d4e83d1d0904daf721132e2bbecc3..4252672ad2aaf03d50e5ea6a681e9964fd9a6137 100644
--- a/net/minecraft/util/BlockUtil.java
+++ b/net/minecraft/util/BlockUtil.java
@@ -138,12 +138,20 @@ public class BlockUtil {
public final BlockPos minCorner;
public final int axis1Size;
public final int axis2Size;
+ public BlockPos foundOrigin; // Anonymous - Fix folia nether portal ticket placement
public FoundRectangle(final BlockPos minCorner, final int axis1Size, final int axis2Size) {
this.minCorner = minCorner;
this.axis1Size = axis1Size;
this.axis2Size = axis2Size;
+ this.foundOrigin = minCorner; // Anonymous - Fix folia nether portal ticket placement - prevent edge conditions(idk if someone would do this so just prevent it)
}
+ // Anonymous start - Fix folia nether portal ticket placement
+ public FoundRectangle withFoundOrigin(BlockPos origin) {
+ this.foundOrigin = origin;
+ return this;
+ }
+ // Anonymous end
}
public static class IntBounds {
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index acc9caf8559cd341ea17d3b58f13cdac7de18564..489011f9af49fa3407038bd2f00439443307d179 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -4851,7 +4851,7 @@ public abstract class Entity
portalInfoCompletable.complete(
new TeleportTransition(destination, Vec3.atCenterOf(targetPos), Vec3.ZERO,
90.0f, 0.0f,
- TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET))
+ TeleportTransition.PLAY_PORTAL_SOUND.then(ent -> ent.placePortalTicket(targetPos))) // Anonymous - Fix folia nether portal ticket placement
);
return;
}
@@ -4863,7 +4863,7 @@ public abstract class Entity
portalInfoCompletable.complete(
net.minecraft.world.level.block.NetherPortalBlock.createDimensionTransition(
destination, portal, originalPortalDirection, relativePos,
- Entity.this, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET)
+ Entity.this, TeleportTransition.PLAY_PORTAL_SOUND.then(ent -> ent.placePortalTicket(portal.foundOrigin)) // Anonymous - Fix folia nether portal ticket placement
)
);
}
diff --git a/net/minecraft/world/level/block/NetherPortalBlock.java b/net/minecraft/world/level/block/NetherPortalBlock.java
index 29fc9521c2c8333c999647dd833899393a838064..e8d2b52a3948755c8d3912a4ad1204cea5f78674 100644
--- a/net/minecraft/world/level/block/NetherPortalBlock.java
+++ b/net/minecraft/world/level/block/NetherPortalBlock.java
@@ -204,7 +204,7 @@ public class NetherPortalBlock extends Block implements Portal {
return BlockUtil.getLargestRectangleAround(found, portalState.getValue(BlockStateProperties.HORIZONTAL_AXIS), 21, Direction.Axis.Y, 21, (pos) -> {
return world.getBlockStateFromEmptyChunk(pos) == portalState;
- });
+ }).withFoundOrigin(found); // Anonymous - Fix folia nether portal ticket placement
}
// Folia end - region threading
@@ -19,51 +19,35 @@ package dev.kaiijumc.kaiiju;
import com.google.common.base.Throwables;
import com.mojang.logging.LogUtils;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ScanResult;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.world.entity.Entity;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.EntityType;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jspecify.annotations.NonNull;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
@SuppressWarnings("unused")
public class KaiijuEntityLimits {
private static final Logger LOGGER = LogUtils.getLogger();
private static final File CONFIG_FOLDER = new File("luminol_config");
private static final File CONFIG_FOLDER = new File("shiroha_config");
protected static final String HEADER =
"Per region entity limits for Kaiiju.\n"
+ "If there are more of particular entity type in a region than limit, entity ticking will be throttled.\n"
+ "Example: for Wither limit 100 & 300 Withers in a region -> 100 Withers tick every tick & every Wither ticks every 3 ticks.\n"
+ "Available entities: GlowSquid, Ambient, Bat, Animal, Bee, Cat, Chicken, Cod, Cow, Dolphin, Fish, FishSchool, Fox, Golem, IronGolem, "
+ "MushroomCow, Ocelot, Panda, Parrot, Perchable, Pig, PolarBear, PufferFish, Rabbit, Salmon, Sheep, Snowman, Squid, TropicalFish, Turtle, "
+ "WaterAnimal, Wolf, Allay, Axolotl, Camel, Frog, Tadpole, Goat, Horse, HorseAbstract, HorseChestedAbstract, HorseDonkey, HorseMule, "
+ "HorseSkeleton, HorseZombie, Llama, LlamaTrader, Sniffer, EnderCrystal, EnderDragon, Wither, ArmorStand, Hanging, ItemFrame, Leash, "
+ "Painting, GlowItemFrame, FallingBlock, Item, TNTPrimed, Blaze, CaveSpider, Creeper, Drowned, Enderman, Endermite, Evoker, Ghast, "
+ "GiantZombie, Guardian, GuardianElder, IllagerAbstract, IllagerIllusioner, IllagerWizard, MagmaCube, Monster, MonsterPatrolling, Phantom, "
+ "ZombifiedPiglin, Pillager, Ravager, Shulker, Silverfish, Skeleton, SkeletonAbstract, SkeletonStray, SkeletonWither, Slime, Spider, Strider, Vex, "
+ "Vindicator, Witch, Zoglin, Zombie, ZombieHusk, ZombieVillager, Hoglin, Piglin, PiglinAbstract, PiglinBrute, Warden, Villager, "
+ "VillagerTrader, Arrow, DragonFireball, Egg, EnderPearl, EnderSignal, EvokerFangs, Fireball, FireballFireball, Fireworks, FishingHook, "
+ "LargeFireball, LlamaSpit, Potion, Projectile, ProjectileThrowable, ShulkerBullet, SmallFireball, Snowball, SpectralArrow, ThrownExpBottle, "
+ "ThrownTrident, TippedArrow, WitherSkull, Raider, ChestBoat, Boat, MinecartAbstract, MinecartChest, MinecartCommandBlock, MinecartContainer, "
+ "MinecartFurnace, MinecartHopper, MinecartMobSpawner, MinecartRideable, MinecartTNT\n";
+ "Entity names are named under the registry of minecraft's entity type";
protected static final File ENTITY_LIMITS_FILE = new File(CONFIG_FOLDER, "kaiiju_entity_limits.yml");
public static YamlConfiguration entityLimitsConfig;
public static boolean enabled = false;
protected static Map<Class<? extends Entity>, EntityLimit> entityLimits;
static final String ENTITY_PREFIX = "Entity";
public static void init() {
init(true);
}
@@ -84,8 +68,9 @@ public class KaiijuEntityLimits {
entityLimitsConfig.options().header(HEADER);
entityLimitsConfig.options().copyDefaults(true);
entityLimitsConfig.set("enabled", enabled);
entityLimitsConfig.set("Axolotl.limit", 1000);
entityLimitsConfig.set("Axolotl.removal", 2000);
entityLimitsConfig.set("axolotl.limit", 1000);
entityLimitsConfig.set("axolotl.removal", 2000);
try {
entityLimitsConfig.save(ENTITY_LIMITS_FILE);
} catch (IOException ex) {
@@ -96,62 +81,42 @@ public class KaiijuEntityLimits {
enabled = entityLimitsConfig.getBoolean("enabled");
entityLimits = new Object2ObjectOpenHashMap<>();
try (ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages("net.minecraft.world.entity").scan()) {
Map<String, ClassInfo> entityClasses = new HashMap<>();
for (ClassInfo classInfo : scanResult.getAllClasses()) {
Class<?> entityClass = Class.forName(classInfo.getName());
if (Entity.class.isAssignableFrom(entityClass)) {
String entityName = extractEntityName(entityClass.getSimpleName());
entityClasses.put(entityName, classInfo);
}
}
for (String key : entityLimitsConfig.getKeys(false)) {
if (key.equals("enabled")) {
continue;
}
if (!entityClasses.containsKey(key)) {
LOGGER.error("Unknown entity '" + key + "' in kaiiju-entity-limits.yml, skipping");
continue;
}
int limit = entityLimitsConfig.getInt(key + ".limit");
int removal = entityLimitsConfig.getInt(key + ".removal");
if (limit < 1) {
LOGGER.error(key + " has a limit less than the minimum of 1, ignoring");
continue;
}
if (removal <= limit && removal != -1) {
LOGGER.error(key + " has a removal limit that is less than or equal to its limit, setting removal to limit * 10");
removal = limit * 10;
}
entityLimits.put((Class<? extends Entity>) Class.forName(entityClasses.get(key).getName()), new EntityLimit(limit, removal));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
if (!enabled) {
return;
}
}
public static EntityLimit getEntityLimit(Entity entity) {
return entityLimits.get(entity.getClass());
}
for (String key : entityLimitsConfig.getKeys(false)) {
if (key.equals("enabled")) {
continue;
}
private static String extractEntityName(String input) {
int prefixLength = ENTITY_PREFIX.length();
final Optional<Holder.Reference<EntityType<?>>> lookup = BuiltInRegistries.ENTITY_TYPE.get(Identifier.fromNamespaceAndPath(Identifier.DEFAULT_NAMESPACE, key));
if (lookup.isEmpty()) {
LOGGER.error("Unknown entity '{}' in kaiiju-entity-limits.yml, skipping", key);
continue;
}
if (input.length() <= prefixLength || !input.startsWith(ENTITY_PREFIX)) {
return input;
} else {
return input.substring(prefixLength);
final EntityType<?> value = lookup.get().value();
int limit = entityLimitsConfig.getInt(key + ".limit");
int removal = entityLimitsConfig.getInt(key + ".removal");
if (limit < 1) {
LOGGER.error("{} has a limit less than the minimum of 1, ignoring", key);
continue;
}
if (removal <= limit && removal != -1) {
LOGGER.error("{} has a removal limit that is less than or equal to its limit, setting removal to limit * 10", key);
removal = limit * 10;
}
value.entityLimit = new EntityLimit(limit, removal);
}
}
public record EntityLimit(int limit, int removal) {
@Override
public String toString() {
public @NonNull String toString() {
return "EntityLimit{limit=" + limit + ", removal=" + removal + "}";
}
}
@@ -45,7 +45,8 @@ public class KaiijuEntityThrottler {
public EntityThrottlerReturn tickLimiterShouldSkip(Entity entity) {
EntityThrottlerReturn retVal = new EntityThrottlerReturn();
if (entity.isRemoved()) return retVal;
KaiijuEntityLimits.EntityLimit entityLimit = KaiijuEntityLimits.getEntityLimit(entity);
KaiijuEntityLimits.EntityLimit entityLimit = entity.getType().entityLimit;
if (entityLimit != null) {
TickInfo tickInfo = entityLimitTickInfoMap.computeIfAbsent(entityLimit, el -> {