aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0687-Rate-options-and-timings-for-sensors-and-behaviors.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/0687-Rate-options-and-timings-for-sensors-and-behaviors.patch')
-rw-r--r--patches/server/0687-Rate-options-and-timings-for-sensors-and-behaviors.patch207
1 files changed, 207 insertions, 0 deletions
diff --git a/patches/server/0687-Rate-options-and-timings-for-sensors-and-behaviors.patch b/patches/server/0687-Rate-options-and-timings-for-sensors-and-behaviors.patch
new file mode 100644
index 0000000000..74cf0c5264
--- /dev/null
+++ b/patches/server/0687-Rate-options-and-timings-for-sensors-and-behaviors.patch
@@ -0,0 +1,207 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Phoenix616 <[email protected]>
+Date: Mon, 28 Jun 2021 22:38:29 +0100
+Subject: [PATCH] Rate options and timings for sensors and behaviors
+
+This adds config options to specify the tick rate for sensors
+ and behaviors of different entity types as well as timings
+ for those in order to be able to have some metrics as to which
+ ones might need tweaking.
+
+diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
+index b47b7dce26805badd422c1867733ff4bfd00e9f4..b27021a42cbed3f0648a8d0903d00d03922ae221 100644
+--- a/src/main/java/co/aikar/timings/MinecraftTimings.java
++++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
+@@ -113,6 +113,14 @@ public final class MinecraftTimings {
+ return Timings.ofSafe("Minecraft", "## tickEntity - " + entityType + " - " + type, tickEntityTimer);
+ }
+
++ public static Timing getBehaviorTimings(String type) {
++ return Timings.ofSafe("## Behavior - " + type);
++ }
++
++ public static Timing getSensorTimings(String type, int rate) {
++ return Timings.ofSafe("## Sensor - " + type + " (Default rate: " + rate + ")");
++ }
++
+ /**
+ * Get a named timer for the specified tile entity type to track type specific timings.
+ * @param entity
+diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+index 960240240d76d408489f5c0274d56b0496c69928..5ad05615e4dc1cc14112ab40e435a72672eedb87 100644
+--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+@@ -9,8 +9,10 @@ import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+ import net.minecraft.world.entity.MobCategory;
+ import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray.EngineMode;
+ import java.util.HashMap;
++import java.util.Locale;
+ import java.util.Map;
+ import org.bukkit.Bukkit;
++import org.bukkit.configuration.ConfigurationSection;
+ import org.bukkit.configuration.file.YamlConfiguration;
+ import org.spigotmc.SpigotWorldConfig;
+
+@@ -883,4 +885,57 @@ public class PaperWorldConfig {
+ private void playerCrammingDamage() {
+ allowPlayerCrammingDamage = getBoolean("allow-player-cramming-damage", allowPlayerCrammingDamage);
+ }
++
++ private com.google.common.collect.Table<String, String, Integer> sensorTickRates;
++ private com.google.common.collect.Table<String, String, Integer> behaviorTickRates;
++ private void tickRates() {
++ config.addDefault("world-settings.default.tick-rates.sensor.villager.secondarypoisensor", 40);
++ config.addDefault("world-settings.default.tick-rates.behavior.villager.validatenearbypoi", -1); // Example
++ log("Tick rates:");
++ sensorTickRates = loadTickRates("sensor");
++ behaviorTickRates = loadTickRates("behavior");
++ }
++
++ private com.google.common.collect.Table<String, String, Integer> loadTickRates(String type) {
++ log(" " + type + ":");
++ com.google.common.collect.Table<String, String, Integer> table = com.google.common.collect.HashBasedTable.create();
++
++ ConfigurationSection typeSection = config.getConfigurationSection("world-settings." + worldName + ".tick-rates." + type);
++ if (typeSection == null) {
++ typeSection = config.getConfigurationSection("world-settings.default.tick-rates." + type);
++ }
++ if (typeSection != null) {
++ for (String entity : typeSection.getKeys(false)) {
++ ConfigurationSection entitySection = typeSection.getConfigurationSection(entity);
++ if (entitySection != null) {
++ log(" " + entity + ":");
++ for (String typeName : entitySection.getKeys(false)) {
++ if (entitySection.isInt(typeName)) {
++ int tickRate = entitySection.getInt(typeName);
++ table.put(entity.toLowerCase(Locale.ROOT), typeName.toLowerCase(Locale.ROOT), tickRate);
++ log(" " + typeName + ": " + tickRate);
++ }
++ }
++ }
++ }
++ }
++
++ if (table.isEmpty()) {
++ log(" None configured");
++ }
++ return table;
++ }
++
++ public int getBehaviorTickRate(String typeName, String entityType, int def) {
++ return getIntOrDefault(behaviorTickRates, typeName, entityType, def);
++ }
++
++ public int getSensorTickRate(String typeName, String entityType, int def) {
++ return getIntOrDefault(sensorTickRates, typeName, entityType, def);
++ }
++
++ private int getIntOrDefault(com.google.common.collect.Table<String, String, Integer> table, String rowKey, String columnKey, int def) {
++ Integer rate = table.get(columnKey, rowKey);
++ return rate != null && rate > -1 ? rate : def;
++ }
+ }
+diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java
+index b1212e162ba938b3abe0df747a633ba9cbbe57c8..c24ff2ef1054523e58892c2b35080cffb6ab744a 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java
++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java
+@@ -14,6 +14,10 @@ public abstract class Behavior<E extends LivingEntity> {
+ private long endTimestamp;
+ private final int minDuration;
+ private final int maxDuration;
++ // Paper start - configurable behavior tick rate and timings
++ private final String configKey;
++ private final co.aikar.timings.Timing timing;
++ // Paper end
+
+ public Behavior(Map<MemoryModuleType<?>, MemoryStatus> requiredMemoryState) {
+ this(requiredMemoryState, 60);
+@@ -27,6 +31,15 @@ public abstract class Behavior<E extends LivingEntity> {
+ this.minDuration = minRunTime;
+ this.maxDuration = maxRunTime;
+ this.entryCondition = requiredMemoryState;
++ // Paper start - configurable behavior tick rate and timings
++ String key = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName());
++ int lastSeparator = key.lastIndexOf('.');
++ if (lastSeparator != -1) {
++ key = key.substring(lastSeparator + 1);
++ }
++ this.configKey = key.toLowerCase(java.util.Locale.ROOT);
++ this.timing = co.aikar.timings.MinecraftTimings.getBehaviorTimings(configKey);
++ // Paper end
+ }
+
+ public Behavior.Status getStatus() {
+@@ -34,11 +47,19 @@ public abstract class Behavior<E extends LivingEntity> {
+ }
+
+ public final boolean tryStart(ServerLevel world, E entity, long time) {
++ // Paper start - behavior tick rate
++ int tickRate = world.paperConfig.getBehaviorTickRate(this.configKey, entity.getType().id, -1);
++ if (tickRate > -1 && time < this.endTimestamp + tickRate) {
++ return false;
++ }
++ // Paper end
+ if (this.hasRequiredMemories(entity) && this.checkExtraStartConditions(world, entity)) {
+ this.status = Behavior.Status.RUNNING;
+ int i = this.minDuration + world.getRandom().nextInt(this.maxDuration + 1 - this.minDuration);
+ this.endTimestamp = time + (long)i;
++ this.timing.startTiming(); // Paper - behavior timings
+ this.start(world, entity, time);
++ this.timing.stopTiming(); // Paper - behavior timings
+ return true;
+ } else {
+ return false;
+@@ -49,11 +70,13 @@ public abstract class Behavior<E extends LivingEntity> {
+ }
+
+ public final void tickOrStop(ServerLevel world, E entity, long time) {
++ this.timing.startTiming(); // Paper - behavior timings
+ if (!this.timedOut(time) && this.canStillUse(world, entity, time)) {
+ this.tick(world, entity, time);
+ } else {
+ this.doStop(world, entity, time);
+ }
++ this.timing.stopTiming(); // Paper - behavior timings
+
+ }
+
+diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java
+index c940a910a435b20297eca493c7b27fd69be54e86..f3b8e253a5bfc3f68121dbe656ae7e2ac0f0eb1c 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java
++++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java
+@@ -19,8 +19,21 @@ public abstract class Sensor<E extends LivingEntity> {
+ private static final TargetingConditions ATTACK_TARGET_CONDITIONS_IGNORE_INVISIBILITY_AND_LINE_OF_SIGHT = TargetingConditions.forCombat().range(16.0D).ignoreLineOfSight().ignoreInvisibilityTesting();
+ private final int scanRate;
+ private long timeToTick;
++ // Paper start - configurable sensor tick rate and timings
++ private final String configKey;
++ private final co.aikar.timings.Timing timing;
++ // Paper end
+
+ public Sensor(int senseInterval) {
++ // Paper start - configurable sensor tick rate and timings
++ String key = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName());
++ int lastSeparator = key.lastIndexOf('.');
++ if (lastSeparator != -1) {
++ key = key.substring(lastSeparator + 1);
++ }
++ this.configKey = key.toLowerCase(java.util.Locale.ROOT);
++ this.timing = co.aikar.timings.MinecraftTimings.getSensorTimings(configKey, senseInterval);
++ // Paper end
+ this.scanRate = senseInterval;
+ this.timeToTick = (long)RANDOM.nextInt(senseInterval);
+ }
+@@ -31,8 +44,12 @@ public abstract class Sensor<E extends LivingEntity> {
+
+ public final void tick(ServerLevel world, E entity) {
+ if (--this.timeToTick <= 0L) {
+- this.timeToTick = (long)this.scanRate;
++ // Paper start - configurable sensor tick rate and timings
++ this.timeToTick = world.paperConfig.getSensorTickRate(this.configKey, entity.getType().id, this.scanRate);
++ this.timing.startTiming();
++ // Paper end
+ this.doTick(world, entity);
++ this.timing.stopTiming(); // Paper - sensor timings
+ }
+
+ }